Catalogue produits : variantes à options, prix en centimes, catégories, collections, traductions et réservation de stock sûre
Installer
genpm add @core/catalogCe que vous obtenez
- Source dans src/lib/catalog/, 8 fichiers. (38,6 ko)
- Règles IA dans src/lib/catalog/AGENTS.md, plus les fichiers de règles de l’IDE.
- Variables d’environnement ajoutées à .env.example : STORE_CURRENCY.
- Résout @core/contracts, @core/db, @core/money, @core/rich-text pour vous.
README
Ce paquet n’a pas de README.
Voici exactement ce que lit votre IA quand elle travaille dans src/lib/catalog. Rien d’autre n’est ajouté à son contexte.
@core/catalog — rules for AI agents
Purpose
Products for a store: up to 3 options (Size, Color…) and their variants with SKU, price/compare-at/cost in minor
units, stock with backorder rules, weight and image; categories (tree), manual ordered collections, tags, attributes,
per-locale translations, media references (@core/media ids), sitemap/search sources and admin resources.
reserveStock locks the variant row so two buyers can't get the last unit. No cart, prices rules or multi-warehouse.
Map
index.ts— public API:createProduct,updateProduct,getProduct,listProducts,reserveStock,releaseStock,upsertCategory,setCollection,categoryTree,lowStockVariants,catalogAdminResources.products.ts— products, variants, listing, stock.taxonomy.ts— categories and collections.sources.ts—productSitemapSource,productSearchSource.admin.ts— admin resources.schema.ts— tables.
Integration
- Env:
STORE_CURRENCY(ISO code, defaultEUR). Migrations as insrc/lib/db/AGENTS.md. - Product page:
const p = await getProduct(slug, { locale })(404 when null); showp.variantswithformat(v.price, locale)(@core/money) andv.availability; renderp.descriptionwith @core/rich-text. - Listing:
listProducts({ category, tag, collection, sort, page, minPrice, maxPrice, inStock }). - Register
productSitemapSource()(seo),productSearchSource()(search) and...catalogAdminResources()(admin). - JSON-LD with
jsonLd.product(@core/seo) usingavailabilityand the real price. - Verify: create a product with two variants in the admin and see it at
/products/<slug>.
Conventions
- Prices are integers in
STORE_CURRENCY; the server price is the only valid price (carts recompute it). - Reserve stock only inside the order transaction (
reserveStock(id, qty, tx)); release it on cancel/expiry. - Archive products instead of deleting them: orders keep references to their variants.
- Permissions:
products:read|create|update|delete.
Don't
- Don't show a compare-at price that isn't real (the EU requires the lowest price of the last 30 days for discounts).
- Don't decrement
stockwith plain updates outsidereserveStock/releaseStock. - Don't expose
costAmountin public pages or APIs.
# @core/catalog — rules for AI agents
## Purpose
Products for a store: up to 3 options (Size, Color…) and their variants with SKU, price/compare-at/cost in minor
units, stock with backorder rules, weight and image; categories (tree), manual ordered collections, tags, attributes,
per-locale translations, media references (@core/media ids), sitemap/search sources and admin resources.
`reserveStock` locks the variant row so two buyers can't get the last unit. No cart, prices rules or multi-warehouse.
## Map
- `index.ts` — public API: `createProduct`, `updateProduct`, `getProduct`, `listProducts`, `reserveStock`, `releaseStock`, `upsertCategory`, `setCollection`, `categoryTree`, `lowStockVariants`, `catalogAdminResources`.
- `products.ts` — products, variants, listing, stock. `taxonomy.ts` — categories and collections.
- `sources.ts` — `productSitemapSource`, `productSearchSource`. `admin.ts` — admin resources. `schema.ts` — tables.
## Integration
1. Env: `STORE_CURRENCY` (ISO code, default `EUR`). Migrations as in `src/lib/db/AGENTS.md`.
2. Product page: `const p = await getProduct(slug, { locale })` (404 when null); show `p.variants` with
`format(v.price, locale)` (@core/money) and `v.availability`; render `p.description` with @core/rich-text.
3. Listing: `listProducts({ category, tag, collection, sort, page, minPrice, maxPrice, inStock })`.
4. Register `productSitemapSource()` (seo), `productSearchSource()` (search) and `...catalogAdminResources()` (admin).
5. JSON-LD with `jsonLd.product` (@core/seo) using `availability` and the real price.
6. Verify: create a product with two variants in the admin and see it at `/products/<slug>`.
## Conventions
- Prices are integers in `STORE_CURRENCY`; the server price is the only valid price (carts recompute it).
- Reserve stock only inside the order transaction (`reserveStock(id, qty, tx)`); release it on cancel/expiry.
- Archive products instead of deleting them: orders keep references to their variants.
- Permissions: `products:read|create|update|delete`.
## Don't
- Don't show a compare-at price that isn't real (the EU requires the lowest price of the last 30 days for discounts).
- Don't decrement `stock` with plain updates outside `reserveStock`/`releaseStock`.
- Don't expose `costAmount` in public pages or APIs.
L’arborescence exacte qui sera injectée, après .genpmignore. Épinglée à
// Fuentes de sitemap y buscador con los productos activos.
import { and, asc, eq, gt } from 'drizzle-orm';
import { defineSearchSource, defineSitemapSource } from '../contracts/index.ts';
import { getDb } from '../db/index.ts';
import { toPlainText } from '../rich-text/index.ts';
import { type Product, products } from './schema.ts';
async function* active(): AsyncGenerator<Product> {
let after = '';
for (;;) {
const rows = await getDb().select().from(products).where(and(eq(products.status, 'active'), gt(products.id, after))).orderBy(asc(products.id)).limit(500);
yield* rows;
if (rows.length < 500) return;
after = rows.at(-1)!.id;
}
}
const defaultPath = (slug: string) => `/products/${slug}`;
export const productSitemapSource = (path = defaultPath) =>
defineSitemapSource({
name: 'products',
async *urls() {
for await (const p of active()) yield { loc: path(p.slug), lastmod: p.updatedAt };
},
});
export const productSearchSource = (path = defaultPath) =>
defineSearchSource({
type: 'product',
async *documents() {
for await (const p of active())
yield {
id: p.id,
type: 'product',
url: path(p.slug),
title: p.name,
body: [p.brand, p.tags.join(' '), Object.values(p.attributes).join(' '), p.description ? toPlainText(p.description) : ''].filter(Boolean).join('\n'),
updatedAt: p.updatedAt,
};
},
});
Ce paquet ne déclare aucun serveur MCP.
| Version | Commit | Publié | Analyse |
|---|---|---|---|
| 1.0.0 | 79d3468 | il y a 5 heures | analyse réussie |
- npm
- zod ^4.0.0
- proposé
- GenPM propose la commande npm et ne l’exécute que si vous acceptez.
- analyse
- analyse réussie · 0 problème
- commit
- v1.0.0 → 79d3468925acbde57d17a18a32e9d4bdefc28b5e · vérifié après téléchargement
- scripts
- Aucun. GenPM n’exécute jamais le code des paquets.
- licence
- MIT
- Qualité
- 100/100
- Licence reconnuevalidé
- AGENTS.md explique son objectifvalidé
- AGENTS.md donne les étapes d’intégrationvalidé
- AGENTS.md liste conventions ou interditsvalidé
- Contient des testsvalidé
- Analyse de sécurité réussievalidé
- Publié au cours des 6 derniers moisvalidé
- Éditeur vérifiévalidé
- Résumé et mots-clésvalidé
- signalement
- Vous avez repéré un problème ?