diff --git a/api-graph.dot b/api-graph.dot index 959ad59..f93181e 100644 --- a/api-graph.dot +++ b/api-graph.dot @@ -25,7 +25,7 @@ digraph api { label="Catalog & Products"; labeljust="l"; fontsize=15; style="rounded,filled"; fillcolor="#202a3a"; color="#3f4c5f"; fontcolor="#e2e8f0"; margin=14; - Article [label=<
Article
/article
POST/Create article in category
GET/{sku}Get article by SKU
GET/{sku}/articlelistGet Stückliste (bundle item…
GET/{sku}/childrenList child articles of a pa…
GET/{sku}/historyGet article history by SKU
GET/{sku}/optionslistGet options list for an art…
GET/export.zipExport articles as ZIP
POST/{sku}/childrenCreate and attach a new chi…
POST/{sku}/imageAdd article image
POST/{sku}/parentToggle parent mode for an a…
POST/{sku}/printPrint article label
PUT/{sku}/articlelistSet Stückliste (bundle item…
PUT/{sku}/brandSet or clear article brand …
PUT/{sku}/categoriesReplace article categories …
PUT/{sku}/childrenAttach an existing article …
PUT/{sku}/eansReplace article EANs by SKU
PUT/{sku}/images/orderReorder article images
PUT/{sku}/optionslistSet options list for an art…
PUT/{sku}/pricesReplace POS prices by SKU (…
PUT/{sku}/track_stockSet article track_stock fla…
PUT/{sku}/weightSet article weight by SKU
PATCH/{sku}Update article by SKU
DELETE/{sku}Delete article by SKU
DELETE/{sku}/children/{childSku}Remove a child article from…
DELETE/{sku}/image/{fullHash}Delete article image
>]; + Article [label=<
Article
/article
POST/Create article in category
GET/{sku}Get article by SKU
GET/{sku}/articlelistGet Stückliste (bundle item…
GET/{sku}/childrenList child articles of a pa…
GET/{sku}/historyGet article history by SKU
GET/{sku}/optionslistGet options list for an art…
GET/export.zipExport articles as ZIP
GET/historyQuery company-wide article …
POST/{sku}/childrenCreate and attach a new chi…
POST/{sku}/imageAdd article image
POST/{sku}/parentToggle parent mode for an a…
POST/{sku}/printPrint article label
PUT/{sku}/articlelistSet Stückliste (bundle item…
PUT/{sku}/brandSet or clear article brand …
PUT/{sku}/categoriesReplace article categories …
PUT/{sku}/childrenAttach an existing article …
PUT/{sku}/eansReplace article EANs by SKU
PUT/{sku}/images/orderReorder article images
PUT/{sku}/optionslistSet options list for an art…
PUT/{sku}/pricesReplace POS prices by SKU (…
PUT/{sku}/track_stockSet article track_stock fla…
PUT/{sku}/weightSet article weight by SKU
PATCH/{sku}Update article by SKU
DELETE/{sku}Delete article by SKU
DELETE/{sku}/children/{childSku}Remove a child article from…
DELETE/{sku}/image/{fullHash}Delete article image
>]; Category [label=<
Category
/category
POST/Create category
GET/{id}/articlesArticles in category
GET/export.zipExport categories as ZIP
GET/treeCategory tree
POST/{id}/imageAdd category image
PUT/orderReorder sibling categories
PATCH/{id}Update category (rename or …
DELETE/{id}Delete category
DELETE/{id}/imageDelete category image
>]; Brand [label=<
Brand
/brand
GET/List brands
POST/Create brand
POST/{id}/imageAdd or replace brand image
PATCH/{id}Rename brand
DELETE/{id}Delete brand
DELETE/{id}/imageDelete brand image
>]; Unit [label=<
Unit
/unit
GET/List units
PUT/Upsert unit
DELETE/Delete unit
>]; @@ -61,7 +61,7 @@ digraph api { style="rounded,filled"; fillcolor="#202a3a"; color="#3f4c5f"; fontcolor="#e2e8f0"; margin=14; Stock [label=<
Stock
/stock
POST/acceptAccept delivery manifest it…
POST/adjustAdjust stock manually
POST/shipShip shipment manifest item…
>]; - Ledger [label=<
Ledger
/ledger
GET/Query ledger by manifest ar…
GET/manifestarticle/{manifestarticleId}Query ledger by manifest ar…
GET/sku/{sku}Query ledger by article SKU
>]; + Ledger [label=<
Ledger
/ledger
GET/Query ledger by manifest ar…
GET/historyQuery company-wide ledger h…
GET/manifestarticle/{manifestarticleId}Query ledger by manifest ar…
GET/sku/{sku}Query ledger by article SKU
>]; Warehouse [label=<
Warehouse
/warehouse
GET/List warehouses
POST/Create warehouse
GET/{id}Get warehouse by ID
PUT/{id}Update warehouse
PUT/orderReorder warehouses
PATCH/{id}Update warehouse (partial)
DELETE/{id}Delete warehouse
>]; } subgraph cluster_finance { @@ -104,6 +104,7 @@ digraph api { Legend [label=<
API Graph Legend
GETSafe retrieval / query
POSTCreate resource / action
PUTFull replace / collection update
PATCHPartial entity update
DELETERemove resource
in#Inbound arrival port on resource
▪—▶Relational reference / dataflow
>]; } SubagentSchedule [label=<
SubagentSchedule
/subagentschedule
GET/List subagent schedules
POST/Create subagent schedule
GET/{id}Get subagent schedule by ID
PUT/{id}Update subagent schedule
DELETE/{id}Delete subagent schedule
>]; + Carrier [label=<
Carrier
/carrier
GET/List carriers
POST/Create carrier
GET/{id}Get carrier by ID
PUT/orderReorder carriers
PATCH/{id}Update carrier
DELETE/{id}Delete carrier
>]; Backup [label=<
Backup
/backup
GET/List backups and service st…
GET/{id}/vfsList VFS files in a backup
POST/{id}/vfs/recoverRecover VFS file from a bac…
>]; Order:ep_get__order__id_:e -> Entity:in2:n [color="#ff6b6b", fontcolor="#ff6b6b", tooltip="Order → Entity (entityId)", label=" entityId ", weight=3]; diff --git a/api-graph.svg b/api-graph.svg index 57c8c9b..248d05f 100644 --- a/api-graph.svg +++ b/api-graph.svg @@ -11,23 +11,23 @@ cluster_identity - -Identity & Access + +Identity & Access cluster_crm - -Entities & CRM + +Entities & CRM cluster_catalog - + Catalog & Products cluster_properties - -Properties & Attributes + +Properties & Attributes cluster_purchasing @@ -36,23 +36,23 @@ cluster_sales - + Sales & Fulfillment cluster_inventory - + Inventory & Warehousing cluster_finance - -Finance & Payments + +Finance & Payments cluster_media - -Media & Storage + +Media & Storage cluster_pos @@ -72,202 +72,202 @@ Auth - - -Auth -/auth - - - -GET -/.well-known/oauth-authorization-server -OAuth 2.0 Authorization Ser… - + + +Auth +/auth + - -GET -/.well-known/oauth-protected-resource -OAuth 2.0 Protected Resourc… - + +GET +/.well-known/oauth-authorization-server +OAuth 2.0 Authorization Ser… + - -GET -/me -Current user - + +GET +/.well-known/oauth-protected-resource +OAuth 2.0 Protected Resourc… + - -POST -/login -Login with Google ID token - + +GET +/me +Current user + - -POST -/logout -Logout - + +POST +/login +Login with Google ID token + - -PUT -/selected-company -Set selected company + +POST +/logout +Logout + + + +PUT +/selected-company +Set selected company Company - - - - - - - - -Company -/company - - - -GET -/ -List companies - + + + + + + + + +Company +/company + - -POST -/ -Create company - + +GET +/ +List companies + - -GET -/export -Export company catalog as z… - + +POST +/ +Create company + - -GET -/history -Get company history - + +GET +/export +Export company catalog as z… + - -POST -/export -Export company catalog as z… - + +GET +/history +Get company history + - -POST -/history -Add company history entry - + +POST +/export +Export company catalog as z… + - -POST -/import -Import company catalog from… - + +POST +/history +Add company history entry + - -PUT -/{id} -Update company - + +POST +/import +Import company catalog from… + - -DELETE -/{id} -Delete company + +PUT +/{id} +Update company + + + +DELETE +/{id} +Delete company CompanySetting - - - -CompanySetting -/companysetting - - - -GET -/company/setting -List company settings - + + + +CompanySetting +/companysetting + - -GET -/company/setting/{key} -Get company setting by key - + +GET +/company/setting +List company settings + - -PUT -/company/setting/{key} -Upsert company setting + +GET +/company/setting/{key} +Get company setting by key + + + +PUT +/company/setting/{key} +Upsert company setting Company:w->CompanySetting:n - - + + -  settings   +  settings   Customergroup - - - - - -Customergroup -/customergroup - - - -GET -/ -List customer groups - + + + + + +Customergroup +/customergroup + - -POST -/ -Create customer group - + +GET +/ +List customer groups + - -PUT -/order -Reorder customer groups - + +POST +/ +Create customer group + - -PATCH -/{id} -Update customer group - + +PUT +/order +Reorder customer groups + - -DELETE -/{id} -Delete customer group + +PATCH +/{id} +Update customer group + + + +DELETE +/{id} +Delete customer group Company:e->Customergroup:n - - + + -  poscustomergroup   +  poscustomergroup   @@ -341,147 +341,147 @@ Company:w->Category:n - + -  root_category   +  root_category   Number - - -Number -/number - - - -GET -/ -List number sequences - + + +Number +/number + - -PATCH -/{id} -Update number sequence + +GET +/ +List number sequences + + + +PATCH +/{id} +Update number sequence Number:w->Company:n - - + + -  companyId   +  companyId   Entity - - - - - - -Entity -/entity - - - -GET -/ -List entities - + + + + + + +Entity +/entity + - -POST -/ -Create entity - + +GET +/ +List entities + - -GET -/{entityId}/address -List entity addresses - + +POST +/ +Create entity + - -GET -/{entityId}/contact -List entity contacts - + +GET +/{entityId}/address +List entity addresses + - -GET -/{id} -Get entity - + +GET +/{entityId}/contact +List entity contacts + - -GET -/next-number -Peek next customer number - + +GET +/{id} +Get entity + - -POST -/{entityId}/address -Create entity address - + +GET +/next-number +Peek next customer number + - -POST -/{entityId}/contact -Create entity contact - + +POST +/{entityId}/address +Create entity address + - -PATCH -/{entityId}/address/{id} -Update entity address - + +POST +/{entityId}/contact +Create entity contact + - -PATCH -/{entityId}/contact/{id} -Update entity contact - + +PATCH +/{entityId}/address/{id} +Update entity address + - -PATCH -/{id} -Update entity - + +PATCH +/{entityId}/contact/{id} +Update entity contact + - -DELETE -/{entityId}/address/{id} -Delete entity address - + +PATCH +/{id} +Update entity + - -DELETE -/{entityId}/contact/{id} -Delete entity contact - + +DELETE +/{entityId}/address/{id} +Delete entity address + - -DELETE -/{id} -Delete entity + +DELETE +/{entityId}/contact/{id} +Delete entity contact + + + +DELETE +/{id} +Delete entity Entity:e->Customergroup:n - - + + -  customergroupId   +  customergroupId   @@ -547,132 +547,138 @@ Export articles as ZIP - -POST -/{sku}/children -Create and attach a new chi… + +GET +/history +Query company-wide article … - -POST -/{sku}/image -Add article image + +POST +/{sku}/children +Create and attach a new chi… - -POST -/{sku}/parent -Toggle parent mode for an a… + +POST +/{sku}/image +Add article image - -POST -/{sku}/print -Print article label + +POST +/{sku}/parent +Toggle parent mode for an a… - -PUT -/{sku}/articlelist -Set Stückliste (bundle item… + +POST +/{sku}/print +Print article label - -PUT -/{sku}/brand -Set or clear article brand … + +PUT +/{sku}/articlelist +Set Stückliste (bundle item… - -PUT -/{sku}/categories -Replace article categories … + +PUT +/{sku}/brand +Set or clear article brand … - -PUT -/{sku}/children -Attach an existing article … + +PUT +/{sku}/categories +Replace article categories … - -PUT -/{sku}/eans -Replace article EANs by SKU + +PUT +/{sku}/children +Attach an existing article … - -PUT -/{sku}/images/order -Reorder article images + +PUT +/{sku}/eans +Replace article EANs by SKU - -PUT -/{sku}/optionslist -Set options list for an art… + +PUT +/{sku}/images/order +Reorder article images - -PUT -/{sku}/prices -Replace POS prices by SKU (… + +PUT +/{sku}/optionslist +Set options list for an art… - -PUT -/{sku}/track_stock -Set article track_stock fla… + +PUT +/{sku}/prices +Replace POS prices by SKU (… - -PUT -/{sku}/weight -Set article weight by SKU + +PUT +/{sku}/track_stock +Set article track_stock fla… - -PATCH -/{sku} -Update article by SKU + +PUT +/{sku}/weight +Set article weight by SKU - -DELETE -/{sku} -Delete article by SKU + +PATCH +/{sku} +Update article by SKU - -DELETE -/{sku}/children/{childSku} -Remove a child article from… + +DELETE +/{sku} +Delete article by SKU - -DELETE -/{sku}/image/{fullHash} -Delete article image + +DELETE +/{sku}/children/{childSku} +Remove a child article from… + + + +DELETE +/{sku}/image/{fullHash} +Delete article image Article:e->Customergroup:n - - + + -  prices   +  prices   Article:ne->Article:n - - + + -  bundles & variants   +  bundles & variants   @@ -733,11 +739,11 @@ Article:w->Brand:n - + -  brand   +  brand   @@ -770,7 +776,7 @@ Article:w->Unit:n - + @@ -779,204 +785,204 @@ Property - - - - -Property -/propertyname - - - -GET -/ -List property names - + + + + +Property +/propertyname + - -POST -/ -Create property name - + +GET +/ +List property names + - -GET -/article/{sku}/property -List article properties - + +POST +/ +Create property name + - -GET -/category/{id}/property -List category properties - + +GET +/article/{sku}/property +List article properties + - -PUT -/article/{sku}/property -Bulk set article properties - + +GET +/category/{id}/property +List category properties + - -PUT -/category/{id}/property -Bulk set category properties - + +PUT +/article/{sku}/property +Bulk set article properties + - -PUT -/order -Reorder property names - + +PUT +/category/{id}/property +Bulk set category properties + - -PATCH -/{id} -Update property name - + +PUT +/order +Reorder property names + - -DELETE -/{id} -Delete property name - + +PATCH +/{id} +Update property name + - -DELETE -/article/{sku}/property/{propertyId} -Delete article property - + +DELETE +/{id} +Delete property name + - -DELETE -/category/{id}/property/{propertyId} -Delete category property + +DELETE +/article/{sku}/property/{propertyId} +Delete article property + + + +DELETE +/category/{id}/property/{propertyId} +Delete category property Article:e->Property:n - - + + -  properties   +  properties   Attribute - - - - -Attribute -/attributename - - - -GET -/ -List attribute names - + + + + +Attribute +/attributename + - -POST -/ -Create attribute name - + +GET +/ +List attribute names + - -GET -/{attributeId}/value -List values for an attribute - + +POST +/ +Create attribute name + - -GET -/article/{sku}/attributevalue -List article attribute valu… - + +GET +/{attributeId}/value +List values for an attribute + - -GET -/category/{id}/attributevalue -List category attribute val… - + +GET +/article/{sku}/attributevalue +List article attribute valu… + - -POST -/{attributeId}/value -Create value for an attribu… - + +GET +/category/{id}/attributevalue +List category attribute val… + - -POST -/attributevalue/{id}/image -Add or replace attribute va… - + +POST +/{attributeId}/value +Create value for an attribu… + - -PUT -/{attributeId}/value/order -Reorder values of an attrib… - + +POST +/attributevalue/{id}/image +Add or replace attribute va… + - -PUT -/article/{sku}/attributevalue -Bulk set article attribute … - + +PUT +/{attributeId}/value/order +Reorder values of an attrib… + - -PUT -/category/{id}/attributevalue -Bulk set category attribute… - + +PUT +/article/{sku}/attributevalue +Bulk set article attribute … + - -PUT -/order -Reorder attribute names - + +PUT +/category/{id}/attributevalue +Bulk set category attribute… + - -PATCH -/{id} -Update attribute name - + +PUT +/order +Reorder attribute names + - -PATCH -/attributevalue/{id} -Update attribute value - + +PATCH +/{id} +Update attribute name + - -DELETE -/{id} -Delete attribute name - + +PATCH +/attributevalue/{id} +Update attribute value + - -DELETE -/attributevalue/{id} -Delete attribute value - + +DELETE +/{id} +Delete attribute name + - -DELETE -/attributevalue/{id}/image -Delete attribute value image + +DELETE +/attributevalue/{id} +Delete attribute value + + + +DELETE +/attributevalue/{id}/image +Delete attribute value image Article:e->Attribute:n - - + + -  attributes   +  attributes   @@ -1030,42 +1036,42 @@ Image - - - - - - -Image -/image - - - -GET -/{fullHash} -Full image by hash - + + + + + + +Image +/image + - -GET -/smallthumb/{fullHash} -Small thumb image by hash - + +GET +/{fullHash} +Full image by hash + - -GET -/thumb/{fullHash} -Thumb image by hash + +GET +/smallthumb/{fullHash} +Small thumb image by hash + + + +GET +/thumb/{fullHash} +Thumb image by hash Article:e->Image:n - - + + -  photos   +  photos   @@ -1091,41 +1097,41 @@ Category:e->Property:n - - + + -  properties   +  properties   Category:e->Attribute:n - - + + -  attributes   +  attributes   Category:e->Image:n - - + + -  image   +  image   Brand:e->Image:n - - + + -  image   +  image   @@ -1183,21 +1189,21 @@ Property:e->Company:n - - + + -  companyId   +  companyId   Attribute:e->Image:n - - + + -  image   +  image   @@ -1249,11 +1255,11 @@ Supplier:e->Entity:n - - + + -  entityId   +  entityId   @@ -1354,38 +1360,44 @@ Ledger - - - - - -Ledger -/ledger - - - -GET -/ -Query ledger by manifest ar… - - - -GET -/manifestarticle/{manifestarticleId} -Query ledger by manifest ar… - - - -GET -/sku/{sku} -Query ledger by article SKU + + + + + +Ledger +/ledger + + + +GET +/ +Query ledger by manifest ar… + + + +GET +/history +Query company-wide ledger h… + + + +GET +/manifestarticle/{manifestarticleId} +Query ledger by manifest ar… + + + +GET +/sku/{sku} +Query ledger by article SKU Delivery:e->Ledger:n - - + +  ledger   @@ -1456,11 +1468,11 @@ Quote:e->Entity:n - - + + -  entityId   +  entityId   @@ -1475,105 +1487,105 @@ Order - - - - - - -Order -/order - - - -GET -/ -List orders - - - -POST -/ -Create order - - - -GET -/{id} -Get order - - - -GET -/{id}/file/{fileId} -Get order attachment file c… - - - -GET -/{id}/payment -List payments of an order - - - -GET -/{id}/shipment -List shipments of an order - - - -GET -/{id}/shipping -List shippings of an order - - - -POST -/{id}/payment -Add payment to an order - - - -POST -/{id}/pdf -Generate and attach order P… - - - -POST -/{id}/shipment -Create shipment for an order - - - -POST -/{id}/shipping -Create shipping for an order - - - -PATCH -/{id} -Update order - - - -DELETE -/{id} -Delete order - - - -DELETE -/{id}/file/{fileId} -Delete order file attachment + + + + + + +Order +/order + + + +GET +/ +List orders + + + +POST +/ +Create order + + + +GET +/{id} +Get order + + + +GET +/{id}/file/{fileId} +Get order attachment file c… + + + +GET +/{id}/payment +List payments of an order + + + +GET +/{id}/shipment +List shipments of an order + + + +GET +/{id}/shipping +List shippings of an order + + + +POST +/{id}/payment +Add payment to an order + + + +POST +/{id}/pdf +Generate and attach order P… + + + +POST +/{id}/shipment +Create shipment for an order + + + +POST +/{id}/shipping +Create shipping for an order + + + +PATCH +/{id} +Update order + + + +DELETE +/{id} +Delete order + + + +DELETE +/{id}/file/{fileId} +Delete order file attachment Quote:e->Order:n - - + +  convert order   @@ -1582,18 +1594,18 @@ Order:e->Entity:n - - + + -  entityId   +  entityId   Order:e->Article:n - - + +  lines.sku   @@ -1665,7 +1677,7 @@ Order:e->Shipment:n - + @@ -1710,33 +1722,33 @@ Order:e->Shipping:n - + -  shippings   +  shippings   Payment - - - -Payment -/payment - - - -DELETE -/{id} -Delete payment + + + +Payment +/payment + + + +DELETE +/{id} +Delete payment Order:e->Payment:n - - + +  payments   @@ -1755,11 +1767,11 @@ Shipment:w->Order:n - - + + -  manifestId   +  manifestId   @@ -1774,47 +1786,47 @@ Package - - - -Package -/package - - - -DELETE -/{id} -Delete package + + + +Package +/package + + + +DELETE +/{id} +Delete package Shipping:e->Package:n - - + + -  packages   +  packages   Package:e->Entity:n - - + + -  addressId   +  addressId   Package:w->Shipping:n - + -  shippingId   +  shippingId   @@ -1857,8 +1869,8 @@ Stock:e->Ledger:n - - + +  ledger   @@ -1929,17 +1941,17 @@ Ledger:w->Article:n - - + + -  sku   +  sku   Ledger:w->Warehouse:n - + @@ -1948,46 +1960,46 @@ Account - - - -Account -/account - - - -GET -/ -List accounts - + + + +Account +/account + - -POST -/ -Create account - + +GET +/ +List accounts + - -DELETE -/{id} -Delete account + +POST +/ +Create account + + + +DELETE +/{id} +Delete account Account:e->Company:n - - + + -  companyId   +  companyId   Payment:w->Order:n - - + +  manifestId   @@ -1996,100 +2008,100 @@ Payment:e->Account:n - - + + -  accountId   +  accountId   Serper - - -Serper -/serper - - - -POST -/image -Crawl image from URL, crop … - + + +Serper +/serper + - -POST -/images -Search images via Serper.de… + +POST +/image +Crawl image from URL, crop … + + + +POST +/images +Search images via Serper.de… Vfs - - - -Vfs -/vfs - - - -GET -/ -List virtual filesystem fil… - + + + +Vfs +/vfs + - -GET -/{*path} -Get a virtual filesystem fi… - + +GET +/ +List virtual filesystem fil… + - -POST -/{*path} -Execute a virtual filesyste… - + +GET +/{*path} +Get a virtual filesystem fi… + - -POST -/applets/restore -Restore system default appl… - + +POST +/{*path} +Execute a virtual filesyste… + - -POST -/mkdir -Create directory in virtual… - + +POST +/applets/restore +Restore system default appl… + - -POST -/rename -Rename or move a virtual fi… - + +POST +/mkdir +Create directory in virtual… + - -POST -/skills/restore -Restore system default skil… - + +POST +/rename +Rename or move a virtual fi… + - -POST -/upload -Upload files to virtual fil… - + +POST +/skills/restore +Restore system default skil… + - -PUT -/{*path} -Create or overwrite a virtu… - + +POST +/upload +Upload files to virtual fil… + - -DELETE -/{*path} -Delete a virtual filesystem… + +PUT +/{*path} +Create or overwrite a virtu… + + + +DELETE +/{*path} +Delete a virtual filesystem… @@ -2152,11 +2164,11 @@ POSTerminal:e->Company:n - - + + -  companyId   +  companyId   @@ -2222,11 +2234,11 @@ Printer:e->Company:n - - + + -  companyId   +  companyId   @@ -2286,11 +2298,11 @@ LabelTemplate:e->Company:n - - + + -  companyId   +  companyId   @@ -2404,11 +2416,11 @@ ModelConversation:e->Vfs:n - - + + -  vfs workspace   +  vfs workspace   @@ -2498,8 +2510,8 @@ MCP:w->Order:n - - + +  order tools   @@ -2542,8 +2554,8 @@ Events:w->Ledger:n - - + +  ledger sse   @@ -2641,31 +2653,75 @@ /{id} Delete subagent schedule - + +Carrier + + +Carrier +/carrier + + + +GET +/ +List carriers + + + +POST +/ +Create carrier + + + +GET +/{id} +Get carrier by ID + + + +PUT +/order +Reorder carriers + + + +PATCH +/{id} +Update carrier + + + +DELETE +/{id} +Delete carrier + + + Backup - - -Backup -/backup - - - -GET -/ -List backups and service st… - - - -GET -/{id}/vfs -List VFS files in a backup - - - -POST -/{id}/vfs/recover -Recover VFS file from a bac… + + +Backup +/backup + + + +GET +/ +List backups and service st… + + + +GET +/{id}/vfs +List VFS files in a backup + + + +POST +/{id}/vfs/recover +Recover VFS file from a bac… diff --git a/docs/api/README.md b/docs/api/README.md index 4cac0f8..bf83d61 100644 --- a/docs/api/README.md +++ b/docs/api/README.md @@ -39,6 +39,7 @@ Generated from `@openapi` annotations in [`src/api/routes/`](../../src/api/route | [`routes/account/_id.md`](routes/account/_id.md) | `DELETE /account/{id}` | | [`routes/article/create.md`](routes/article/create.md) | `POST /article` | | [`routes/article/export.zip.md`](routes/article/export.zip.md) | `GET /article/export.zip` | +| [`routes/article/history-list.md`](routes/article/history-list.md) | `GET /article/history` | | [`routes/article/delete.md`](routes/article/delete.md) | `DELETE /article/{sku}` | | [`routes/article/get.md`](routes/article/get.md) | `GET /article/{sku}` | | [`routes/article/update.md`](routes/article/update.md) | `PATCH /article/{sku}` | @@ -166,6 +167,7 @@ Generated from `@openapi` annotations in [`src/api/routes/`](../../src/api/route | [`routes/labeltemplate/update.md`](routes/labeltemplate/update.md) | `PATCH /labeltemplate/{id}` | | [`routes/labeltemplate/update.md`](routes/labeltemplate/update.md) | `PUT /labeltemplate/{id}` | | [`routes/ledger.md`](routes/ledger.md) | `GET /ledger` | +| [`routes/ledger/history.md`](routes/ledger/history.md) | `GET /ledger/history` | | [`routes/ledger/manifestarticle/_manifestarticleId.md`](routes/ledger/manifestarticle/_manifestarticleId.md) | `GET /ledger/manifestarticle/{manifestarticleId}` | | [`routes/ledger/sku/_sku.md`](routes/ledger/sku/_sku.md) | `GET /ledger/sku/{sku}` | | [`routes/mcp.md`](routes/mcp.md) | `POST /mcp` | diff --git a/docs/api/routes-all.md b/docs/api/routes-all.md index c426fb8..462cfa0 100644 --- a/docs/api/routes-all.md +++ b/docs/api/routes-all.md @@ -1,6 +1,6 @@ # Dash API Routes Overview (All) -Overview of all 261 API endpoints across all modules. +Overview of all 263 API endpoints across all modules. ### Notation @@ -83,6 +83,9 @@ _none_ #### Export articles as ZIP — `GET /article/export.zip` - Params: `query: categoryId?: int` - Returns: `200 zip` +#### Query company-wide article history — `GET /article/history` +- Params: `query: offset?: int, limit?: int, search?: str, seekMonths?: int` +- Returns: `200 { history: { id: int, date: str, sku: str, historytext: str, name?: str|null }[], total: int, unfilteredTotal: int, offset: int, limit: int }` #### Delete article by SKU — `DELETE /article/{sku}` - Params: `sku: str, query: cascade?: bool` - Returns: `204 void` @@ -528,6 +531,9 @@ _none_ #### Query ledger by manifest article ID or SKU — `GET /ledger` - Params: `query: manifestarticle_id?: int, sku?: str, transaction_type?: str` - Returns: `200 { ledger: T15[] }` +#### Query company-wide ledger history — `GET /ledger/history` +- Params: `query: offset?: int, limit?: int, search?: str, seekMonths?: int` +- Returns: `200 { ledger: { id: int, date: str, transaction_type: str, transaction_text: str, sku?: str|null, name?: str|null, amount?: num }[], total: int, unfilteredTotal: int, offset: int, limit: int }` #### Query ledger by manifest article ID — `GET /ledger/manifestarticle/{manifestarticleId}` - Params: `manifestarticleId: int, query: transaction_type?: str` - Returns: `200 { ledger: T15[] }` diff --git a/docs/api/routes.md b/docs/api/routes.md index 53663a5..60355b7 100644 --- a/docs/api/routes.md +++ b/docs/api/routes.md @@ -1,6 +1,6 @@ # Dash API Routes Overview -Overview of all 186 API endpoints across all modules. +Overview of all 188 API endpoints across all modules. ### Notation @@ -50,6 +50,9 @@ Params: path values first, then `query:` and `body:` (`body?` = optional body). #### Create article in category — `POST /article` - Params: `body: { categoryId: int, name: str, desc?: str, seo?: str, track_stock?: bool }` - Returns: `201 { article: T26 }` +#### Query company-wide article history — `GET /article/history` +- Params: `query: offset?: int, limit?: int, search?: str, seekMonths?: int` +- Returns: `200 { history: { id: int, date: str, sku: str, historytext: str, name?: str|null }[], total: int, unfilteredTotal: int, offset: int, limit: int }` #### Delete article by SKU — `DELETE /article/{sku}` - Params: `sku: str, query: cascade?: bool` - Returns: `204 void` @@ -410,6 +413,9 @@ _none_ #### Query ledger by manifest article ID or SKU — `GET /ledger` - Params: `query: manifestarticle_id?: int, sku?: str, transaction_type?: str` - Returns: `200 { ledger: T11[] }` +#### Query company-wide ledger history — `GET /ledger/history` +- Params: `query: offset?: int, limit?: int, search?: str, seekMonths?: int` +- Returns: `200 { ledger: { id: int, date: str, transaction_type: str, transaction_text: str, sku?: str|null, name?: str|null, amount?: num }[], total: int, unfilteredTotal: int, offset: int, limit: int }` #### Query ledger by manifest article ID — `GET /ledger/manifestarticle/{manifestarticleId}` - Params: `manifestarticleId: int, query: transaction_type?: str` - Returns: `200 { ledger: T11[] }` diff --git a/docs/api/routes/article/history-list.md b/docs/api/routes/article/history-list.md new file mode 100644 index 0000000..18939d8 --- /dev/null +++ b/docs/api/routes/article/history-list.md @@ -0,0 +1,52 @@ +# `GET /article/history` + +Protected. Requires a valid session cookie (`credentials: 'include'`). + +Query company-wide article history + +Queries article change history across all articles for the authenticated user's selected company. +Supports pagination, search filter, and date cutoff via `seekMonths`. + + +## Query parameters + +| Param | Required | Type | Description | +|-------|----------|------|-------------| +| `offset` | no | integer | Paging offset | +| `limit` | no | integer | Page size | +| `search` | no | string | Optional search filter across SKU, article name, and history text | +| `seekMonths` | no | integer | Negative integer cutoff months ago (e.g. -13) | + +## Response `200` + +Paged article history list + +```json +{ + "history": [ + { + "id": 1, + "date": "2026-08-10T00:00:00.000Z", + "sku": "…", + "name": "…", + "historytext": "…" + } + ], + "total": 1, + "unfilteredTotal": 1, + "offset": 1, + "limit": 1 +} +``` + +## Errors + +| Status | Description | +|--------|-------------| +| 400 | Validation error or no company selected — `{"error":"…"}` | +| 401 | Unauthorized — `{"error":"…"}` | +| 403 | Not authorized — `{"error":"…"}` | + +--- + +_Generated from `@openapi` JSDoc. Do not edit by hand — run `npm run docs:api`._ diff --git a/docs/api/routes/ledger/history.md b/docs/api/routes/ledger/history.md new file mode 100644 index 0000000..4ab2010 --- /dev/null +++ b/docs/api/routes/ledger/history.md @@ -0,0 +1,54 @@ +# `GET /ledger/history` + +Protected. Requires a valid session cookie (`credentials: 'include'`). + +Query company-wide ledger history + +Queries ledger entries across all articles for the authenticated user's selected company. +Supports pagination, search filter, and date cutoff via `seekMonths`. + + +## Query parameters + +| Param | Required | Type | Description | +|-------|----------|------|-------------| +| `offset` | no | integer | Paging offset | +| `limit` | no | integer | Page size | +| `search` | no | string | Optional search filter across SKU, article name, manifest number, external number, transaction type, and transaction text | +| `seekMonths` | no | integer | Negative integer cutoff months ago (e.g. -1) | + +## Response `200` + +Paged ledger history list + +```json +{ + "ledger": [ + { + "id": 1, + "date": "2026-08-10T00:00:00.000Z", + "sku": "…", + "name": "…", + "transaction_type": "…", + "transaction_text": "…", + "amount": 1 + } + ], + "total": 1, + "unfilteredTotal": 1, + "offset": 1, + "limit": 1 +} +``` + +## Errors + +| Status | Description | +|--------|-------------| +| 400 | Validation error or no company selected — `{"error":"…"}` | +| 401 | Unauthorized — `{"error":"…"}` | +| 403 | Not authorized — `{"error":"…"}` | + +--- + +_Generated from `@openapi` JSDoc. Do not edit by hand — run `npm run docs:api`._ diff --git a/src/api/routes/article/crud.js b/src/api/routes/article/crud.js index c4cd664..91b18ab 100644 --- a/src/api/routes/article/crud.js +++ b/src/api/routes/article/crud.js @@ -257,7 +257,155 @@ export function register(app, basePath = '') { /** * @openapi - * /article/{sku}: + * /article/history: + * get: + * tags: [Article] + * summary: Query company-wide article history + * description: | + * Queries article change history across all articles for the authenticated user's selected company. + * Supports pagination, search filter, and date cutoff via `seekMonths`. + * security: + * - cookieAuth: [] + * x-markdown: article/history-list.md + * parameters: + * - in: query + * name: offset + * schema: + * type: integer + * minimum: 0 + * default: 0 + * description: Paging offset + * - in: query + * name: limit + * schema: + * type: integer + * minimum: 1 + * maximum: 1000 + * default: 50 + * description: Page size + * - in: query + * name: search + * schema: + * type: string + * description: Optional search filter across SKU, article name, and history text + * - in: query + * name: seekMonths + * schema: + * type: integer + * description: Negative integer cutoff months ago (e.g. -13) + * responses: + * 200: + * description: Paged article history list + * content: + * application/json: + * schema: + * type: object + * required: [history, total, unfilteredTotal, offset, limit] + * properties: + * history: + * type: array + * items: + * type: object + * required: [id, date, sku, historytext] + * properties: + * id: + * type: integer + * date: + * type: string + * format: date-time + * sku: + * type: string + * name: + * type: string + * nullable: true + * historytext: + * type: string + * total: + * type: integer + * unfilteredTotal: + * type: integer + * offset: + * type: integer + * limit: + * type: integer + * 400: + * description: Validation error or no company selected + * content: + * application/json: + * schema: + * $ref: '#/components/schemas/Error' + * 401: + * description: Unauthorized + * content: + * application/json: + * schema: + * $ref: '#/components/schemas/Error' + * 403: + * description: Not authorized + * content: + * application/json: + * schema: + * $ref: '#/components/schemas/Error' + */ + // #region GET /article/history + + app.get(`${basePath}/article/history`, async (req, res) => { + const companyId = req.user.selectedCompanyId; + if (companyId == null) { + return res.status(400).json({ error: 'No company selected' }); + } + + const rawOffset = req.query.offset; + const rawLimit = req.query.limit; + + let offset = 0; + let limit = 50; + + if (rawOffset !== undefined) { + offset = parseInt(rawOffset, 10); + if (!Number.isInteger(offset) || offset < 0) { + return res.status(400).json({ error: 'offset must be an integer >= 0' }); + } + } + + if (rawLimit !== undefined) { + limit = parseInt(rawLimit, 10); + if (!Number.isInteger(limit) || limit < 1 || limit > 1000) { + return res.status(400).json({ error: 'limit must be an integer between 1 and 1000' }); + } + } + + const search = typeof req.query.search === 'string' && req.query.search.trim() !== '' + ? req.query.search.trim() + : undefined; + + let seekMonths = undefined; + if (req.query.seekMonths !== undefined && req.query.seekMonths !== '') { + const parsedSeek = parseInt(req.query.seekMonths, 10); + if (!Number.isInteger(parsedSeek)) { + return res.status(400).json({ error: 'seekMonths must be an integer' }); + } + seekMonths = parsedSeek; + } + + try { + const result = await db.listHistory(req.user.id, { + offset, + limit, + search, + seekMonths, + }); + res.status(200).json(result); + } catch (error) { + const status = articleErrorStatus(error); + if (status === 500) console.error('List article history failed:', error); + res.status(status).json({ error: error.message }); + } + }); + + // #endregion + + /** * @openapi * /article/{sku}: * get: diff --git a/src/api/routes/article/shared.js b/src/api/routes/article/shared.js index 29df5fe..7da8ebc 100644 --- a/src/api/routes/article/shared.js +++ b/src/api/routes/article/shared.js @@ -43,6 +43,9 @@ export function parseFullHash(value) { export function articleErrorStatus(error) { if (error.message === 'No company selected') return 400; + if (error.message === 'Invalid offset') return 400; + if (error.message === 'Invalid limit') return 400; + if (error.message === 'Invalid seekMonths') return 400; if (error.message === 'Unsupported image format' || error.message?.includes('unsupported image format')) return 400; if (error.message === 'Not authorized') return 403; if (error.message === 'Parent not found') return 404; diff --git a/src/api/routes/ledger.js b/src/api/routes/ledger.js index 2cb0973..3d4bb0f 100644 --- a/src/api/routes/ledger.js +++ b/src/api/routes/ledger.js @@ -12,6 +12,9 @@ function requireSelectedCompany(req) { function ledgerErrorStatus(error) { if (error.message === 'No company selected') return 400; + if (error.message === 'Invalid offset') return 400; + if (error.message === 'Invalid limit') return 400; + if (error.message === 'Invalid seekMonths') return 400; if (error.message === 'Not authorized') return 403; if (error.message === 'Company not found') return 404; if (error.message === 'Manifest article not found') return 404; @@ -281,4 +284,160 @@ export function register(app, basePath = '') { }); // #endregion + + /** + * @openapi + * /ledger/history: + * get: + * tags: [Ledger] + * summary: Query company-wide ledger history + * description: | + * Queries ledger entries across all articles for the authenticated user's selected company. + * Supports pagination, search filter, and date cutoff via `seekMonths`. + * security: + * - cookieAuth: [] + * x-markdown: ledger/history.md + * parameters: + * - in: query + * name: offset + * schema: + * type: integer + * minimum: 0 + * default: 0 + * description: Paging offset + * - in: query + * name: limit + * schema: + * type: integer + * minimum: 1 + * maximum: 1000 + * default: 50 + * description: Page size + * - in: query + * name: search + * schema: + * type: string + * description: Optional search filter across SKU, article name, manifest number, external number, transaction type, and transaction text + * - in: query + * name: seekMonths + * schema: + * type: integer + * description: Negative integer cutoff months ago (e.g. -1) + * responses: + * 200: + * description: Paged ledger history list + * content: + * application/json: + * schema: + * type: object + * required: [ledger, total, unfilteredTotal, offset, limit] + * properties: + * ledger: + * type: array + * items: + * type: object + * required: [id, date, transaction_type, transaction_text] + * properties: + * id: + * type: integer + * date: + * type: string + * format: date-time + * sku: + * type: string + * nullable: true + * name: + * type: string + * nullable: true + * transaction_type: + * type: string + * transaction_text: + * type: string + * amount: + * type: number + * total: + * type: integer + * unfilteredTotal: + * type: integer + * offset: + * type: integer + * limit: + * type: integer + * 400: + * description: Validation error or no company selected + * content: + * application/json: + * schema: + * $ref: '#/components/schemas/Error' + * 401: + * description: Unauthorized + * content: + * application/json: + * schema: + * $ref: '#/components/schemas/Error' + * 403: + * description: Not authorized + * content: + * application/json: + * schema: + * $ref: '#/components/schemas/Error' + */ + // #region GET /ledger/history + + app.get(`${basePath}/ledger/history`, async (req, res) => { + const selected = requireSelectedCompany(req); + if (selected.error) { + return res.status(400).json({ error: selected.error }); + } + + const rawOffset = req.query.offset; + const rawLimit = req.query.limit; + + let offset = 0; + let limit = 50; + + if (rawOffset !== undefined) { + offset = parseInt(rawOffset, 10); + if (!Number.isInteger(offset) || offset < 0) { + return res.status(400).json({ error: 'offset must be an integer >= 0' }); + } + } + + if (rawLimit !== undefined) { + limit = parseInt(rawLimit, 10); + if (!Number.isInteger(limit) || limit < 1 || limit > 1000) { + return res.status(400).json({ error: 'limit must be an integer between 1 and 1000' }); + } + } + + const search = typeof req.query.search === 'string' && req.query.search.trim() !== '' + ? req.query.search.trim() + : undefined; + + let seekMonths = undefined; + if (req.query.seekMonths !== undefined && req.query.seekMonths !== '') { + const parsedSeek = parseInt(req.query.seekMonths, 10); + if (!Number.isInteger(parsedSeek)) { + return res.status(400).json({ error: 'seekMonths must be an integer' }); + } + seekMonths = parsedSeek; + } + + try { + const result = await db.listHistory(req.user.id, { + offset, + limit, + search, + seekMonths, + }); + res.status(200).json(result); + } catch (error) { + const status = ledgerErrorStatus(error); + if (status === 500) console.error('List ledger history failed:', error); + res.status(status).json({ error: error.message }); + } + }); + + // #endregion } + diff --git a/src/db/article.js b/src/db/article.js index 6acb0f2..be78a47 100644 --- a/src/db/article.js +++ b/src/db/article.js @@ -15,6 +15,11 @@ export async function getHistoryBySku(googleAuthId, sku, opts) { return store.article.getHistoryBySku(googleAuthId, sku, opts); } +export async function listHistory(googleAuthId, opts) { + const store = await getStore(); + return store.article.listHistory(googleAuthId, opts); +} + export async function updateBySku(googleAuthId, sku, data) { const store = await getStore(); return store.article.updateBySku(googleAuthId, sku, data); diff --git a/src/db/ledger.js b/src/db/ledger.js index bc77c3e..961738c 100644 --- a/src/db/ledger.js +++ b/src/db/ledger.js @@ -26,3 +26,16 @@ export async function listBySku(googleAuthId, sku, transactionType) { const store = await getStore(); return store.ledger.listBySku(googleAuthId, sku, transactionType); } + +/** + * Lists ledger entries across all articles with pagination, seekMonths, and search. + * + * @param {number} googleAuthId - The id of the Google auth user. + * @param {object} [opts] - Query options. + * @returns {Promise} Paged ledger history. + */ +export async function listHistory(googleAuthId, opts) { + const store = await getStore(); + return store.ledger.listHistory(googleAuthId, opts); +} +