ContentItem
Table content_items.
Each macro value is validated as a number from 0 to 1000000, or null.
Indexes:
studioId, (studioId, type), (studioId, isFeatured), categoryId, (studioId, sortOrder, createdAt).
Relations: category, tags (through ContentItemTag), homeBanners, unlocks.
steps
An array validated by recipeStep:
type is step or tip. text is required.
ContentCategory
Table content_categories.
Unique on
(studioId, name) and (studioId, systemKey).
Every new studio gets the three default categories from defaultContentCategories(locale), named in the studio’s locale (Hebrew, English, French, German, Spanish and Arabic names are defined). They are ordinary editable rows. systemKey is how code finds them after a rename. permanentCategoryForType(type) maps an item type to its default category: recipe and video to their own, everything else to knowledge.
ContentTag and ContentItemTag
Tags are studio-wide.
ContentTag (table content_tags): studioId, name (unique per studio), sortOrder, timestamps.
ContentItemTag (table content_item_tags) is the join table. Its primary key is the pair (itemId, tagId). Both sides cascade. There is an index on tagId.
ContentItemUnlock
Table content_item_unlocks. A restricted item revealed to one trainee.
Unique on
(itemId, clientId).
HomeBanner
Table home_banners. One banner per studio: studioId is unique.
The value lists come from
home-banner/home-banner.schema.ts. They are plain strings in the database.