Track and save on groceries

feat(api): implement products and brands schema

Signed-off-by: Sefa Eyeoglu <contact@scrumplex.net>

+65
+18
packages/api/src/schema/brands.ts
··· 1 + import z from "zod/v4"; 2 + import { pageOptions, paginated } from "./pagination.js"; 3 + 4 + export const Brand = z 5 + .object({ 6 + id: z.coerce.number().int().min(0), 7 + name: z.string(), 8 + }) 9 + .meta({ 10 + description: "Brand schema", 11 + examples: [{ id: 1, name: "Nopro" }], 12 + }); 13 + export const CreateBrand = Brand.omit({ 14 + id: true, 15 + }); 16 + 17 + export const BrandsQuery = pageOptions(Brand.shape.id); 18 + export const Brands = paginated(Brand);
+25
packages/api/src/schema/products.ts
··· 1 + import z from "zod/v4"; 2 + import { pageOptions, paginated } from "./pagination.js"; 3 + import { Brand } from "./brands.js"; 4 + 5 + export const Product = z 6 + .object({ 7 + id: z.coerce.number().int().min(0), 8 + name: z.string(), 9 + brandId: Brand.shape.id, 10 + }) 11 + .meta({ 12 + description: "Product schema", 13 + examples: [{ id: 1, brandId: 1, name: "Not Milk 1l" }], 14 + }); 15 + 16 + export const ExtendedProduct = Product.extend({ 17 + brand: Brand, 18 + }) 19 + 20 + export const CreateProduct = Product.omit({ 21 + id: true, 22 + }); 23 + 24 + export const ProductsQuery = pageOptions(Product.shape.id); 25 + export const Products = paginated(Product);
+22
packages/api/src/spec.ts
··· 3 3 import { Store, Stores } from "./schema/stores.js"; 4 4 import { mkdir, writeFile } from "node:fs/promises"; 5 5 import { apiContract } from "./contract/index.js"; 6 + import { Brand, Brands } from "./schema/brands.js"; 7 + import { ExtendedProduct, Product, Products } from "./schema/products.js"; 6 8 7 9 const generator = new OpenAPIGenerator({ 8 10 schemaConverters: [new ZodToJsonSchemaConverter()], ··· 14 16 version: "1.0.0", 15 17 }, 16 18 commonSchemas: { 19 + Brands: { 20 + strategy: "output", 21 + schema: Brands, 22 + }, 23 + Brand: { 24 + strategy: "output", 25 + schema: Brand, 26 + }, 27 + ExtendedProduct: { 28 + strategy: "output", 29 + schema: ExtendedProduct, 30 + }, 31 + Products: { 32 + strategy: "output", 33 + schema: Products, 34 + }, 35 + Product: { 36 + strategy: "output", 37 + schema: Product, 38 + }, 17 39 Stores: { 18 40 strategy: "output", 19 41 schema: Stores,