feat(seo): generate slugs for brands, categories and products, add GET /sitemap and the Postman collection

This commit is contained in:
MastersGame
2026-11-14 11:08:51 +01:00
parent d07c4df52d
commit 657e8a6b30
26 changed files with 750 additions and 12 deletions

View File

@@ -0,0 +1,3 @@
$kind: collection
variables:
baseUrl: "http://localhost:3000"

View File

@@ -0,0 +1,21 @@
$kind: http-example
request:
url: "{{baseUrl}}/sitemap"
method: GET
headers:
Accept: application/json
response:
statusCode: 200
statusText: OK
headers:
Content-Type: application/json; charset=utf-8
Cache-Control: public, max-age=600
body:
type: json
content: |
{
"brands": [{ "slug": "stray-kids", "updatedAt": "2026-11-08T10:00:00.000Z" }],
"categories": [{ "slug": "albums", "updatedAt": "2026-11-08T10:00:00.000Z" }],
"products": [{ "slug": "ate-digipack", "updatedAt": "2026-11-08T10:00:00.000Z" }]
}
order: 1000

View File

@@ -0,0 +1,16 @@
$kind: http-example
request:
url: "{{baseUrl}}/sync"
method: POST
headers:
Accept: application/json
response:
statusCode: 503
statusText: Service Unavailable
headers:
Content-Type: application/json; charset=utf-8
body:
type: json
content: |
{ "message": "This instance is shutting down, retry in a moment", "error": "Service Unavailable", "statusCode": 503 }
order: 4000

View File

@@ -0,0 +1,17 @@
$kind: http-example
request:
url: "{{baseUrl}}/sync"
method: POST
headers:
Accept: application/json
response:
statusCode: 429
statusText: Too Many Requests
headers:
Content-Type: application/json; charset=utf-8
Retry-After: "30"
body:
type: json
content: |
{ "statusCode": 429, "message": "ThrottlerException: Too Many Requests" }
order: 3000

View File

@@ -0,0 +1,16 @@
$kind: http-example
request:
url: "{{baseUrl}}/sync"
method: POST
headers:
Accept: application/json
response:
statusCode: 409
statusText: Conflict
headers:
Content-Type: application/json; charset=utf-8
body:
type: json
content: |
{ "message": "A Hiboutik synchronization is already in progress", "error": "Conflict", "statusCode": 409 }
order: 2000

View File

@@ -0,0 +1,16 @@
$kind: http-example
request:
url: "{{baseUrl}}/sync"
method: POST
headers:
Accept: application/json
response:
statusCode: 202
statusText: Accepted
headers:
Content-Type: application/json; charset=utf-8
body:
type: json
content: |
{ "message": "Hiboutik synchronization started" }
order: 1000

View File

@@ -0,0 +1,16 @@
$kind: http-example
request:
url: "{{baseUrl}}/sync"
method: POST
headers:
Accept: application/json
response:
statusCode: 500
statusText: Internal Server Error
headers:
Content-Type: application/json; charset=utf-8
body:
type: json
content: |
{ "message": "Internal Server Error", "statusCode": 500 }
order: 5000

View File

@@ -0,0 +1,8 @@
$kind: http-request
description: "Public pages of the storefront (brands enabled, categories displayed on the website, products displayed on the website and not archived) that have a slug, with the date of the last write of their row. The storefront builds its sitemap.xml from it. Answered with Cache-Control: public, max-age=600."
url: "{{baseUrl}}/sitemap"
method: GET
headers:
Accept: application/json
examples: ./.resources/getSitemap.resources/examples
order: 2000

View File

@@ -0,0 +1,26 @@
$kind: http-request
description: |-
Starts a full Hiboutik → database synchronization **in the background** and answers immediately: the request never waits for the sync to end.
**What it syncs**, in dependency order: brands → categories → suppliers → products (with their versions and stocks) → customers (with their addresses and orders). New brands, categories and products get their slug at the end of their step.
**Hiboutik is the source of truth**: brands, categories, suppliers, products and customers missing from Hiboutik are deleted from the database (orders are never deleted). A failed Hiboutik call deletes nothing. A failing item is logged and skipped; the sync goes on and logs a summary at the end. Follow its progress in the server logs.
**One sync at a time**, across all instances (Postgres advisory lock): a call while a sync is running answers `409`.
**Cost**: a sync uses roughly one Hiboutik API call per customer, plus a few per entity type. Hiboutik allows 10,000 calls per month per shop; when its rate limit is reached, the sync stops.
**Responses**
- `202` sync started.
- `409` a sync is already running (on this instance or another one).
- `429` rate limit: 5 calls per minute per IP on this route. `Retry-After` gives the seconds to wait.
- `503` this instance is shutting down: retry, another instance can take the call.
- `500` unexpected error (e.g. database unreachable); details are in the server logs only.
No body, no parameters.
url: "{{baseUrl}}/sync"
method: POST
headers:
Accept: application/json
examples: ./.resources/syncHiboutik.resources/examples
order: 1000