Products
Products in Hoikka support variants, translations, and facets (attributes).
Data Model
Product
├── slug (unique identifier)
├── featuredAsset
├── translations (name, description per language)
├── variants (SKU, price, stock)
└── facetValues (attributes like color, size)Multi-Language Support
Default language (English) fields are stored directly on the products table. Non-default languages (e.g. Finnish) use the product_translations table, managed via TranslationService.
const product = await productService.getById(123);
// Default language fields — directly on the products table
product.name; // "Blue Shirt"
product.slug; // "blue-shirt"
product.description; // "<p>A nice shirt</p>"Translations are edited in the admin panel via language tabs on the main form. See Localization for details.
Variants
Each product has one or more variants:
// Product: "T-Shirt"
// Variants: "T-Shirt - Red / M", "T-Shirt - Blue / L"
const variant = {
sku: "TSHIRT-RED-M",
price: 2999, // cents
stock: 50,
facetValues: [redColor, mediumSize]
};Facets (Attributes)
Facets define product attributes for filtering:
// Facet: "Color"
// Values: "Red", "Blue", "Green"
// Facet: "Size"
// Values: "S", "M", "L", "XL"Products and variants can have facet values assigned for:
- Filtering in collections
- Search refinement
- Variant selection
Search
Full-text search using PostgreSQL:
const results = await productService.list({ search: "shirt" });Admin Operations
// Create product — default language fields go directly on the entity
await productService.create({
name: "Blue Shirt",
slug: "blue-shirt",
description: "..."
});
// Add a Finnish translation
import { translationService } from "$lib/server/services/translations";
await translationService.upsertProductTranslation(productId, "fi", {
name: "Sininen paita",
slug: "sininen-paita",
description: "..."
});
// Variant operations are handled through productService
// See src/lib/server/services/products.ts for variant managementLast updated on