feat(seo): generate slugs for brands, categories and products, add GET /sitemap and the Postman collection (#5)
This commit is contained in:
@@ -65,6 +65,7 @@ Domain notes:
|
||||
- Customers: an email or phone removed in Hiboutik is erased in database (`null`, data minimization).
|
||||
- Dates: Hiboutik sends French local time without offset; `parseHiboutikDate` reads datetimes as `Europe/Paris` whatever the server time zone, and date-only values (date of birth) as midnight UTC.
|
||||
- Orders come from the customer's `sales`: sales already stored as `COMPLETED` and linked to this customer are skipped (an order that lost its customer is fetched again to be linked back), the others are fetched and upserted on `hiboutikSaleId` (`source: STORE` on creation only). `status` is `COMPLETED` or `PENDING`, `orderedAt` is the completion date else the creation date. Lines are replaced on each upsert and snapshot name, version, barcode, price and Hiboutik ids; the `ProductVersion` link is optional (`SetNull`). `unitPrice` is the paid price, taxes and discount included. Quotations are skipped, anonymous sales are never synced (only customers' sales are read), and orders are never deleted.
|
||||
- Slugs (SEO): `Brand`, `Category` and `Product` have a unique `slug`, generated once by `SlugService.assignMissingSlugs` at the end of their sync step and never overwritten by the sync (an admin may replace it). Generation handles the oldest `hiboutikId` first: the slugified name, else (sub-categories only) `<parent name>-<name>`, else `name-<hiboutikId>` on a collision (logged as a warning), else `brand|category|product-<hiboutikId>` for a name without latin letters. `SlugService.changeSlug` keeps the former slug in `SlugRedirect` (for a 301); slugs of redirects stay reserved (an entity may only take back its own former slug). `GET /sitemap` lists the public slugs (brands `enabled`, categories `webEnabled`, products `enabled` and not `archived`) for the storefront's sitemap.xml; only products carry a date, `hiboutikUpdatedAt` (the row's `updatedAt` changes on every sync).
|
||||
- Shared Prisma payload types (e.g. `ProductWithVersions`) live in `prisma/customObjects/`.
|
||||
|
||||
## Input validation
|
||||
@@ -83,7 +84,7 @@ All data coming from API clients (`@Body()`, `@Query()`, `@Param()`) must be val
|
||||
|
||||
## API
|
||||
|
||||
If the Postman plugin is installed, load its `postman:api-engineer` skill before any non-trivial API engineering task (designing, implementing, mocking, testing, monitoring, documenting, deploying). Pure questions and trivial one-line edits do not need it. The local `postman/` and `.postman/` folders are generated by `postman init` and are git-ignored.
|
||||
If the Postman plugin is installed, load its `postman:api-engineer` skill before any non-trivial API engineering task (designing, implementing, mocking, testing, monitoring, documenting, deploying). Pure questions and trivial one-line edits do not need it. The API collection lives in `postman/collections/` as v3 YAML and is versioned with the code: update it with the API, check with `postman collection lint` and `postman workspace diff --push-strategy default`, and only `postman workspace push` with the user's consent. Each developer binds the folder to their own Postman workspace (`.postman/resources.yaml`, git-ignored, created by `postman workspace connect-git <workspace-id>` or `postman init`). Also versioned: `postman/specs/`, `postman/flows/`; git-ignored: skills and SDKs (generated), globals and environments (personal values, secrets).
|
||||
|
||||
## Git workflow
|
||||
|
||||
@@ -92,3 +93,5 @@ The remote is a Gitea instance (`origin`). Use plain `git` or the Gitea CLI (`gt
|
||||
- Never commit or push directly to the integration branch: always push changes on a `feature/<name>` branch.
|
||||
- Merges go into `develop`. Until `develop` exists (early project phase), they go into `main`.
|
||||
- Commit messages follow Conventional Commits (`feat(sync): ...`, `fix(db): ...`).
|
||||
- Commit messages and PR/MR content must contain a single-line title only.
|
||||
Do not include any body description or co-author metadata (e.g., "Co-authored-by: Claude").
|
||||
|
||||
Reference in New Issue
Block a user