catalog: schema v3 — fitment, oemNumbers, priceUpdatedAt, availability tri-state #41

Closed
opened 2026-08-27 06:35:50 +00:00 by yuris · 0 comments
Owner

packages/catalog/index.ts is at schemaVersion: 2 and already carries brand, partNumber, category, price, weightGrams, inStock, shippable, installService. The approved mockups need four things it does not have. Both schemas are .strict() and the store re-parses at build time, so this is a lockstep producer+consumer bump — bump to schemaVersion: 3, no v2 compatibility branch, exactly as #34 did for v2.

Fields

  • fitment: string[] — free-text vehicle strings ("Toyota Avanza 1.3 / 1.5 (2012–2021)"), rendered as the mockup's Kecocokan kendaraan list and the source of the Kendaraan filter facet in #46. Free text, not a year/engine/trim matrix — docs/store-overhaul-spec.md rejects the matrix explicitly.
  • oemNumbers: string[] — cross-reference numbers beside partNumber. Empty array, never null, so consumers need no null branch.
  • priceUpdatedAt: string | null — ISO date backing the spec's recommended "harga per 12 Agustus 2026" treatment. Null when price is null.
  • availability: "ready" | "indent" | "habis" — replaces the boolean inStock. This is the schema's whole reason to bump: indent (orderable but not stocked) is a state the boolean cannot express, and the pesanan sparepart flow in the spec depends on it. Still no stock count — see #40 item 1.

Migration of inStock

inStock is deleted, not kept alongside. Consumers to update in the same change: Product JSON-LD availability in apps/store/app/products/[slug]/page.tsx, the Habis badge in product-card.tsx, the stock badge on the detail page, and the !inStock disabled branch in add-to-cart.tsx (which must now distinguish indent from habis — indent is orderable).

Acceptance

pnpm --filter @garage/catalog test passes with new cases: a v2 payload is rejected with the existing Unsupported catalog schema version message; availability outside the enum is rejected; fitment/oemNumbers reject non-string members; priceUpdatedAt rejects a non-ISO string and rejects being set while price is null. The duplicate-slug superRefine and slug sort still hold. apps/store/scripts/wait-for-catalog.mts still gates the deploy on schema compatibility, so #42 must land before the store build can succeed against production.

`packages/catalog/index.ts` is at `schemaVersion: 2` and already carries `brand`, `partNumber`, `category`, `price`, `weightGrams`, `inStock`, `shippable`, `installService`. The approved mockups need four things it does not have. Both schemas are `.strict()` and the store re-parses at build time, so this is a lockstep producer+consumer bump — bump to `schemaVersion: 3`, no v2 compatibility branch, exactly as #34 did for v2. ### Fields - `fitment: string[]` — free-text vehicle strings (`"Toyota Avanza 1.3 / 1.5 (2012–2021)"`), rendered as the mockup's *Kecocokan kendaraan* list and the source of the *Kendaraan* filter facet in #46. Free text, **not** a year/engine/trim matrix — `docs/store-overhaul-spec.md` rejects the matrix explicitly. - `oemNumbers: string[]` — cross-reference numbers beside `partNumber`. Empty array, never null, so consumers need no null branch. - `priceUpdatedAt: string | null` — ISO date backing the spec's recommended *"harga per 12 Agustus 2026"* treatment. Null when `price` is null. - `availability: "ready" | "indent" | "habis"` — replaces the boolean `inStock`. This is the schema's whole reason to bump: `indent` (orderable but not stocked) is a state the boolean cannot express, and the *pesanan sparepart* flow in the spec depends on it. Still no stock count — see #40 item 1. ### Migration of `inStock` `inStock` is deleted, not kept alongside. Consumers to update in the same change: `Product` JSON-LD `availability` in `apps/store/app/products/[slug]/page.tsx`, the `Habis` badge in `product-card.tsx`, the stock badge on the detail page, and the `!inStock` disabled branch in `add-to-cart.tsx` (which must now distinguish `indent` from `habis` — `indent` is orderable). ### Acceptance `pnpm --filter @garage/catalog test` passes with new cases: a v2 payload is rejected with the existing `Unsupported catalog schema version` message; `availability` outside the enum is rejected; `fitment`/`oemNumbers` reject non-string members; `priceUpdatedAt` rejects a non-ISO string and rejects being set while `price` is null. The duplicate-slug `superRefine` and slug sort still hold. `apps/store/scripts/wait-for-catalog.mts` still gates the deploy on schema compatibility, so #42 must land before the store build can succeed against production.
yuris closed this issue 2026-08-27 11:18:25 +00:00
Sign in to join this conversation.
No labels
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set.

Reference
yuris/garage#41
No description provided.