Luxury Goods and Fashion Intelligence. Implemented workspace domain — 26 capability/foundation libraries under
libs/freya/*, the@freya/contractspackage underlibs/contracts/freya, and five applications underapps/freya/*. TODO Phase 57.
This specification documents what is implemented in code. Every schema, enum,
state machine, endpoint, and event below is grounded in a named source file in
the Freya workspace. Where a capability is described in features.md or
TODOS/phase-57.md but not yet built, it is marked (planned).
The specification is organized to follow a reader top-down: package topology
first, then the foundation layer (@freya/core types and @freya/db
persistence), then the API surface, then the capability libraries, then the
applications, configuration, requirements, and domain boundaries.
Package Topology#
Libraries (libs/freya/*)#
Twenty-six packages, all published under the @freya/* scope at version
0.1.0. Two are foundation packages; the rest are capability libraries owning
one business unit each.
| Package | Directory | Role |
|---|---|---|
@freya/core |
libs/freya/core |
Foundation: shared domain types and utilities |
@freya/db |
libs/freya/db |
Foundation: Drizzle schema, Redis/S3 config, observability |
@freya/fashion |
libs/freya/fashion |
Apparel design pipeline |
@freya/textiles |
libs/freya/textiles |
Dyeing, printing, finishing, vertical integration |
@freya/beauty |
libs/freya/beauty |
Skincare, cosmetics, fragrance, haircare formulation |
@freya/brand |
libs/freya/brand |
Brand architecture, positioning, storytelling, digital presence |
@freya/ecommerce |
libs/freya/ecommerce |
Catalog, cart, checkout, payments, diaspora DTC |
@freya/manufacturing |
libs/freya/manufacturing |
Batch, assembly, cosmetics, textile manufacturing |
@freya/retail |
libs/freya/retail |
Store operations, clienteling, customer experience |
@freya/academy |
libs/freya/academy |
Curriculum, students, certification |
@freya/jewelry |
libs/freya/jewelry |
Ethical gold jewelry, production, craft preservation |
@freya/market-intel |
libs/freya/market-intel |
Trend monitoring, competitive intelligence, market research |
@freya/financials |
libs/freya/financials |
Unit economics, financial planning, startup investment |
@freya/connectors |
libs/freya/connectors |
Cross-domain integration (Asase, Brigid, Cybele, Saraswati, Maat) |
@freya/sota |
libs/freya/sota |
AI design, analytics, computer vision, NLP, blockchain auth, virtual try-on |
@freya/watches |
libs/freya/watches |
Watch line management |
@freya/perfumes |
libs/freya/perfumes |
Fragrance bench, accord design, maceration tracking |
@freya/bridal-events |
libs/freya/bridal-events |
Bridal couture and event wardrobe |
@freya/hair-care |
libs/freya/hair-care |
Afro-textured hair-care formulation |
@freya/home-decor |
libs/freya/home-decor |
Interior textiles and home decor |
@freya/footwear |
libs/freya/footwear |
Footwear design and production |
@freya/eyewear |
libs/freya/eyewear |
Optical and sun eyewear |
@freya/luggage-leather |
libs/freya/luggage-leather |
Luggage and leather goods |
@freya/personal-care |
libs/freya/personal-care |
Personal-care formulation |
@freya/cleaning-products |
libs/freya/cleaning-products |
Detergent and cleaning products |
@freya/textile-finishing |
libs/freya/textile-finishing |
Dye-house, print-house, finishing-line operations |
@freya/contracts (libs/contracts/freya, version 0.1.0) is a separate
contracts package holding the Zod request/response schemas shared across the API
and consuming services.
Applications (apps/freya/*)#
Five applications, all published at version 0.0.1. Their package.json names
collide with library names by design (the apps are not consumed as libraries).
| Package name | Directory | Purpose |
|---|---|---|
@freya/api |
apps/freya/api |
REST + GraphQL + gRPC + WebSocket API surface, OpenAPI spec, event bus |
@freya/studio |
apps/freya/studio |
Design and brand studio: trend boards, collection dashboard, tech-pack editor |
@freya/shop |
apps/freya/shop |
Direct-to-consumer storefront: listing, detail, cart, checkout, subscription box |
@freya/retail |
apps/freya/retail |
Retail-operations app: store dashboard, clienteling, inventory lookup, staff |
@freya/manufacturing |
apps/freya/manufacturing |
Factory-floor app: order management, batch records, quality inspection, waste reporting |
Foundation: @freya/core#
@freya/core (libs/freya/core/src/index.ts) is the type and utility
foundation every capability library imports. Its source modules are
product-types.ts, material-types.ts, supply-chain-types.ts,
brand-customer-types.ts, beauty-types.ts, business-units.ts, and
utilities.ts.
Branded ID Types#
From product-types.ts, six template-literal branded ID types prevent
cross-entity reference confusion at compile time. Each carries a fixed prefix
that makes IDs self-documenting and ensures the TypeScript compiler rejects a
FreyaOrderId where a FreyaProductId is expected.
| Type | Prefix | Identifies |
|---|---|---|
FreyaProductId |
FPRD- |
Product |
FreyaCollectionId |
FCOL- |
Collection |
FreyaOrderId |
FORD- |
Customer order |
FreyaCustomerId |
FCUS- |
Customer |
FreyaVariantId |
FVAR- |
Product variant |
FreyaSkuId |
FSKU- |
SKU |
The ID generators (generateProductId, generateCollectionId,
generateOrderId, generateCustomerId, generateVariantId) build IDs as
PREFIX{hexTimestamp}-{6-hex-sequence}-{4-hex-random}. The monotonic sequence
wraps at 0x1000000.
Product-Domain Enums (product-types.ts)#
These enums define the shared vocabulary for product lifecycle, markets, currencies, seasons, and categories. All capability libraries and the API use these same values.
ProductStatus— the product lifecycle:Concept,InDevelopment,Sampling,PreProduction,InProduction,ReadyToShip,Active,Discontinued.FashionSeason—SS(Spring/Summer),FW(Fall/Winter),Resort,PreFall,Capsule,Perennial.FreyaCurrency—GHS,NGN,USD,GBP,EUR,CAD,ZAR.MarketRegion—Ghana,Nigeria,UK,USA,Canada,Germany,Netherlands,Pan_Africa.ProductCategory— nineteen values:fashion_rtw,fashion_couture,watches,textiles_fabric,textiles_finished,skincare,cosmetics,perfume,hair_care,personal_care,detergent,bridal,jewelry,footwear,eyewear,luggage,interior_textiles,accessories,educational.
Product Entity#
Product (product-types.ts) is the central entity. The table below documents
every field and its meaning.
| Field | Type | Required | Meaning |
|---|---|---|---|
productId |
FreyaProductId |
yes | Branded product identity |
name |
string |
yes | Display name |
description |
string |
yes | Long description |
category |
ProductCategory |
yes | Product category |
buCode |
string |
yes | Owning business-unit code |
brand |
string |
yes | Brand identity |
status |
ProductStatus |
yes | Lifecycle status |
variants |
ReadonlyArray<ProductVariant> |
yes | Sellable variants |
pricingTiers |
ReadonlyArray<PricingTier> |
yes | Multi-tier pricing |
targetMarkets |
ReadonlyArray<MarketRegion> |
yes | Intended markets |
certifications |
ReadonlyArray<string> |
yes | Held certifications |
sustainabilityScore |
number |
yes | Sustainability score |
createdAt / updatedAt |
string |
yes | ISO timestamps |
ProductVariant carries per-SKU details: variantId (FreyaVariantId), sku
(FreyaSkuId), optional barcode, optional size/color/material,
stockByLocation (Record<string, number> — quantity keyed by location),
costGhs, optional weight, and optional dimensions
({ length, width, height }).
PricingTier models multi-tier, multi-currency pricing: tierId, tierName
(one of retail, wholesale, vip, diaspora_premium, trade), prices (a
MultiCurrencyPrice map of currency-code → amount), minimumOrderQuantity,
discountPct.
getPriceForMarket(product, market, tier, currency) resolves a price by looking
up the named tier, preferring the requested currency, and falling back to the
market's default currency via a fixed market→currency map (Ghana→GHS,
Nigeria→NGN, UK→GBP, USA→USD, Canada→CAD,
Germany/Netherlands→EUR, Pan_Africa→GHS).
Collection Entity#
Collection (product-types.ts) groups related products for a season. It
carries: collectionId (FreyaCollectionId), name, brand, season
(FashionSeason), year, theme, optional culturalInspiration, productIds
(array of FreyaProductId), launchDate, targetMarkets, priceRangeGhs
({ min, max }), numberOfLooks, designerName, and a status of concept,
design, production, launched, or archived.
LimitedEdition tracks numbered drops: productId, editionName,
totalUnits, remainingUnits, authenticationCode (8-hex), numbering,
premiumPct, launchAt, optional expiresAt. buildLimitedEdition constructs
it with remainingUnits equal to totalUnits and numbering of
1/{totalUnits}.
Material and Textile Types (material-types.ts)#
These enums and types model the physical materials that go into a luxury product. They cover textiles, leathers, metals, gemstones, chemicals, and botanical ingredients.
Enums:
FiberType—cotton,silk,wool,polyester,viscose,bamboo,hemp,kente_silk,ashanti_cotton,linen,nylon,acrylic,lurex.TextileFinish—wax_print,batik,tie_dye,digital_print,screen_print,embroidery,beading,smocking,applique,plain.AfricanPrintType—Ankara,Kente,Adinkra,Bogolan,Shweshwe,Aso_Oke,Kuba,Brocade.LeatherType—full_grain,top_grain,genuine,bonded,vegan_pu,vegan_cork,suede.MaterialGradeScore—A+,A,B,C,Reject.
Material is the core material record: materialId, name, type (textile,
leather, metal, gemstone, chemical, botanical, packaging),
gradeScore (MaterialGradeScore), supplierId, pricePerUnitGhs, unit
(metre, kg, litre, piece, carat), minimumOrderUnits, leadTimeDays,
certifications, sustainabilityScore.
Textile extends material for woven and knitted fabrics: textileId, name,
composition (array of FiberComposition), weaveType (plain, twill,
satin, jacquard, knit, nonwoven, lace), weightGSM, widthCm,
optional countOrDenier, origin, certifications, sustainabilityRating,
priceGhsPerMeter.
FiberComposition records a single fiber's contribution: fiberType,
percentagePct. Colorway models the precise color specification for a dye
lot: colorwayId, name, pantoneCode, hexCode, rgbValues, dyeFormula,
colorToleranceDeltaE, and four colorfastness ratings (fastnessCrockWet,
fastnessCrockDry, fastnessWash, fastnessLight).
AfricanPrint captures culturally significant textile patterns: printId,
printType, name, culturalOrigin, culturalSignificance, colorways,
repeatPatternCm, minimumOrderMeters, leadTimeDays, optional
artisanCoopName, geoprotectionApplied.
TextileTest records a fabric quality test against a laboratory standard:
testId, textileId, testType (tensile_strength, colorfastness,
shrinkage, pilling, abrasion, bursting_strength), standard, result,
unit, passFailThreshold, passed, testedAt, labName.
Three algorithmic invariants are enforced in code. validateFiberComposition
requires fiber percentages to sum to 100% within ±0.5. classifyTextileWeight
buckets GSM as ultra_light (<100), light (<200), medium (<350), heavy
(≤500), extra_heavy (>500). computeDeltaE is a simplified CIE76-style RGB
color difference calculation used to evaluate colorway matching.
Supply-Chain and Manufacturing Types (supply-chain-types.ts)#
These types model the supplier tier structure, manufacturing order lifecycle, AQL quality inspection logic, and shipment tracking.
Enums:
SupplierTier—tier_1,tier_2,tier_3.SupplierCertification—ISO9001,OEKO_TEX,GOTS,Fairtrade,SEDEX,SA8000,WRAP,FSC.OrderStatus(supply-chain order) —draft,placed,confirmed,in_production,quality_check,ready,shipped,delivered,cancelled.InspectionResult—pass,conditional_pass,fail,pending.
Supplier records everything Freya needs to evaluate and manage a supply
relationship: supplierId, name, country, city, tier, capabilities,
certifications (array of SupplierCertification), leadTimeDays,
minimumOrderValue, currency, performanceScore, onTimeDeliveryPct,
qualityPassRatePct, contactEmail, optional activeContractEnd.
Artisan tracks individual craft practitioners: artisanId, name, craft,
communityName, region, skillLevel (apprentice, journeyman, master,
grandmaster), yearsExperience, dailyCapacityUnits, rateGhsPerDay,
portfolioUrls, fairtradeRegistered.
BOMLine captures one line of a bill of materials: materialId,
materialName, quantityPerUnit, unit, wastageAllowancePct,
totalQuantityRequired, unitCostGhs, totalCostGhs.
ManufacturingOrder (core type) is the production instruction for one product
variant: orderId, productId (FreyaProductId), variantId
(FreyaVariantId), quantity, supplierId, bom (array of BOMLine),
totalBOMCostGhs, manufacturingCostGhs, totalCostGhs, targetStartDate,
targetCompletionDate, status (OrderStatus), qualityInspections (array of
inspection IDs), lotNumber.
QualityInspection records AQL sampling evidence for a batch: inspectionId,
orderId, productId, inspectionType (incoming, in_process, final,
shipment), inspectedUnits, acceptableQualityLevel, defectsFound (array
of { category, severity: critical|major|minor, count }), result
(InspectionResult), inspectorId, inspectedAt, notes.
ShipmentTracking records a physical shipment's movement through customs and
delivery: shipmentId, orderId, carrier, trackingNumber, origin,
destination, optional departedAt, estimatedArrivalAt, optional
actualArrivalAt, customsStatus (not_required, filed, under_review,
cleared, held), status (pending, in_transit, at_customs,
delivered, exception), insuranceValueGhs.
Three AQL quality functions are implemented. computeAQLSampleSize returns
standard sample sizes per lot size (lot <50→5, ≤90→8, ≤150→13, ≤280→20, ≤500→32,
≤1200→50, else 80). evaluateQualityResult returns fail on any critical
defect or majors exceeding the AQL threshold, conditional_pass on minors
exceeding twice that threshold, and pass otherwise. computeSupplierScore is
a weighted aggregate:
performanceScore × 0.4 + onTimeDeliveryPct × 0.3 + qualityPassRatePct × 0.3.
Brand and Customer Types (brand-customer-types.ts)#
These types model brand positioning hierarchies and customer segmentation, which together drive pricing, campaign targeting, and loyalty management.
Enums:
CustomerSegment—fashionista,conscious_consumer,heritage_seeker,luxury_buyer,diaspora_elite,mass_market.LoyaltyTier—bronze,silver,gold,platinum,obsidian.
Brand models a brand's identity and market position: brandId, name,
optional parentBrand, positioning (ultra_luxury, luxury, premium,
accessible_premium, mass), targetSegments, heritageStory,
foundingYear, foundingCountry, designerName, optional logoUrl,
brandColors, brandFonts, optional instagramFollowers,
sustainabilityCommitments.
Customer carries the full profile needed for personalization and loyalty:
customerId (FreyaCustomerId), firstName, lastName, email, optional
phoneNumber, country, city, segment, loyaltyTier, loyaltyPoints,
lifeTimeValueGhs, preferredCurrency, preferredCategories, sizes
(Record<string, string>), optional skinTone/hairType, purchaseCount,
optional lastPurchaseAt, registeredAt.
DiasporaMarket, LoyaltyProgram, and InfluencerPartnership are also defined
here. classifyCustomerSegment derives a segment algorithmically from lifetime
value, purchase count, and category affinity, using the following rules: luxury
affinity + LTV ≥ 50000 → luxury_buyer; LTV ≥ 20000 with ≥10 purchases →
diaspora_elite; heritage affinity with ≥3 purchases → heritage_seeker;
beauty affinity with ≥5 purchases → fashionista; LTV ≥ 5000 with ≥5 purchases
→ conscious_consumer; otherwise mass_market.
Beauty and Formulation Types (beauty-types.ts)#
These types model the scientific and regulatory dimension of beauty product development, covering ingredient chemistry, stability testing, and regulatory submission.
Enums:
FragranceFamily—floral,oriental,woody,fresh,fougere,chypre,gourmand,aquatic.HairType— the twelve Andre Walker classes1A–4C.SkinType—normal,dry,oily,combination,sensitive,mature.FitzpatrickScale— numeric1–6.FormulationStatus—concept,development,stability_testing,approved,production,discontinued.
INCIIngredient records a single ingredient per the INCI naming convention:
inciName, commonName, percentagePct, function (array of strings),
origin (natural, synthetic, nature_identical, biotechnology),
supplierId, safetyAssessmentRef, isActiveIngredient, optional
regulatoryRestriction.
Formulation is the versioned formulation record for a beauty product:
formulationId, name, category (skincare, cosmetics, hair_care,
fragrance, personal_care, detergent), ingredients (array of
INCIIngredient), phRange ({ min, max }), optional viscosityCps,
appearanceDescription, shelfLifeMonths, storageConditions, status
(FormulationStatus), version, createdAt, optional regulatoryRef.
FragranceNote records one ingredient's role in a fragrance accord:
ingredientId, inciName, noteType (top, heart, base), family,
odorIntensity, longevityHours, percentageInAccord.
StabilityTest records a time-point stability test result: testId,
formulationId, protocol (ICH_Q1A, accelerated_40C, cycling,
photo_stability), timePointWeeks, conditions, parameters (record of
{ value, specification, passed }), overallResult (pass, fail,
pending), testedAt.
RegulatorySubmission tracks market-specific regulatory filing: submissionId,
formulationId, market, regulatoryBody (Ghana_FDA, EU_SCCS, US_FDA,
NAFDAC), submissionType (registration, notification, cpsr, renewal),
status (draft, submitted, under_review, approved, rejected),
optional submittedAt, approvedAt, expiryAt, registrationNumber.
Three algorithmic functions are provided. validateINCISum enforces ingredient
percentages summing to 100% ±0.5. computeFragranceAccordStrength weights base
notes ×1.5, heart ×1.2, top ×1.0. getHairTypeRecommendations and
getSkinTypeIngredients return domain-specific product/ingredient guidance per
hair type and skin type.
Business-Unit Catalog (business-units.ts)#
FreyaBusinessUnitCode enumerates the nineteen business units that Freya
manages: fashion, watches, textiles, beauty, perfumes,
bridal-events, ecommerce, manufacturing, hair-care, home-decor,
jewelry, footwear, eyewear, academy, luggage-leather, personal-care,
retail, cleaning-products, textile-finishing.
FREYA_BUSINESS_UNIT_CATALOG is a frozen array of nineteen
FreyaBusinessUnitProfile records. Each profile carries code, packageName
(@freya/...), displayName, summary, primaryCategories,
operatingCapabilities, productionModels, commercialChannels, and
keyMetrics. The assertion assertCompleteFreyaBusinessUnitCatalog enforces
exactly nineteen entries with unique codes and packages, protecting the catalog
against accidental omission.
Core Utilities (utilities.ts)#
utilities.ts provides deterministic helpers used across the capability
libraries so each library does not implement its own version of common
calculations.
- SKU generation —
generateSKU(buCode, category, year, sequence)buildsFSKU-{BU}-{CAT}-{YY}-{SSSS}using a fixed category→3-letter abbreviation map (fashion_rtw→RTW,jewelry→JWL, etc.). - Barcodes —
generateEAN13/validateEAN13ChecksumandgenerateUPCA/validateUPCAChecksumimplement the standard EAN-13 and UPC-A check-digit algorithms. - Currency —
EXCHANGE_RATES_TO_GHSholds fixed GHS conversion rates for everyFreyaCurrency;convertToGHS,convertFromGHS, andformatCurrency(with per-currency symbols) operate on it. - Textile conversions —
yardsToMeters,metersToYards,gsmToOzPerSqYard,denierToTex,threadCountToGSM. - Pantone matching —
GHANA_FASHION_PALETTEis a twelve-color Kente/Ankara palette;findNearestPantonereturns the closest palette color by simplified Delta-E distance. - Error types —
FreyaError(base class, withcodeand optionalbuCode),FreyaValidationError(FREYA_VALIDATION_ERROR),FreyaNotFoundError(FREYA_NOT_FOUND),FreyaBusinessRuleError(FREYA_BUSINESS_RULE_VIOLATION).
Persistence: @freya/db#
@freya/db (libs/freya/db/src) owns all persistence infrastructure for the
Freya domain. Source modules: schema.ts, connection.ts, redis-config.ts,
s3-config.ts, observability.ts, seed.ts. Capability libraries import from
this package to get schema types; they never construct their own database
connections.
PostgreSQL Schema (schema.ts)#
All tables and enums are prefixed freya_. The Drizzle migration filter is
tablesFilter: ['freya_*'] (connection.ts). Tables use UUID primary keys
(uuid('id').defaultRandom()), timezone-aware created_at/updated_at
timestamps, and jsonb columns for nested structures. The pgvector extension
provides vector(1536) embedding columns for catalog, collection,
recommendation, and trend-clustering similarity search.
Schema Enums#
schema.ts declares the following Postgres enums. Note that the Drizzle enum
value sets differ from the @freya/core string-union sets by design:
@freya/core types model in-process domain logic with PascalCase values;
schema.ts enums model persisted Postgres columns with snake_case values. The
two are not kept textually identical.
freya_product_status—concept,in_development,sampling,pre_production,in_production,ready_to_ship,active,discontinued.freya_business_unit—fashion,textiles,beauty,skincare,haircare,fragrance,jewelry,footwear,eyewear,home_decor,luggage,personal_care,detergent,academy,retail,ecommerce,bridal,watches(eighteen values).freya_product_category— sixty-two values grouped by domain: fashion (dress,top,trouser,skirt,jacket,coat,suit,jumpsuit,swimwear,sportswear); accessories (bag,wallet,belt,hat,scarf,gloves,sunglasses,watch); shoes (heels,flats,sandals,boots,sneakers,loafers,oxfords); beauty (foundation,lipstick,eyeshadow,mascara,blush,serum,moisturizer,cleanser,toner,sunscreen); haircare (shampoo,conditioner,treatment,styling,tools,extensions); fragrance (eau_de_parfum,eau_de_toilette,body_mist,candle,diffuser); jewelry (necklace,ring,earring,bracelet,anklet,brooch,cufflinks); home (bedding,curtains,cushion,throw,rug,lampshade); personal care (soap,lotion,deodorant,sanitizer,dental,shaving); detergent (laundry_powder,laundry_liquid,fabric_softener,dishwashing,floor_cleaner).freya_season—SS,FW,Resort,PreFall,Capsule,Bridal,Couture.freya_collection_type—seasonal,capsule,collaboration,limited_edition,bridal,couture.freya_material_type—textile,leather,metal,gemstone,botanical,chemical,synthetic.freya_fiber_type—cotton,silk,wool,polyester,viscose,bamboo,hemp,linen,kente_silk,local_cotton,cashmere,mohair,lyocell,nylon,acrylic.freya_textile_finish—wax_print,batik,tie_dye,digital_print,screen_print,embroidery,beading,smocking,applique,laser_cut,pleating,quilting,burnout.freya_order_status—pending,confirmed,processing,shipped,delivered,cancelled,refunded,return_requested,returned.freya_manufacturing_status—planned,in_progress,quality_check,completed,on_hold,cancelled.freya_quality_result—passed,failed,conditional_pass,pending_retest.freya_customer_segment—vip,premium,regular,new,diaspora,wholesale,corporate.freya_loyalty_tier—bronze,silver,gold,platinum,diamond.freya_currency—GHS,NGN,USD,GBP,EUR,CAD,ZAR,KES.freya_market—ghana,nigeria,kenya,south_africa,uk_diaspora,us_diaspora,canada_diaspora,eu_diaspora.freya_store_type—flagship,pop_up,duty_free,mall_kiosk,market_stall,studio,warehouse,outlet.freya_inspection_type—fabric,garment,cosmetics,jewelry,packaging,finished,raw_materials,in_process.freya_certification_status—pending,approved,rejected,expired,under_review.freya_asset_type—logo,sketch,tech_pack,pattern,cad,mood_board,product_photo,lifestyle_photo,video,ar_model.freya_trend_source—instagram,tiktok,pinterest,runway,street_style,celebrity,editorial,trade_show,sales_data,search.freya_academic_status—enrolled,active,on_leave,graduated,withdrawn,suspended.
Schema Tables#
Twenty-four tables form the persistent core of the domain, exported as the
schema object. Every table uses UUID primary keys and targeted B-tree indexes;
unique indexes enforce the business keys listed at the end of this section.
freya_products— catalog row. Key columns:sku(unique index),ean13,upc_a,name,business_unit,category,status(defaultconcept),brand_id→freya_brands,collection_id→freya_collections,base_price_amount/base_price_currency,market_prices(jsonb),weight_kg,dimensions_cm,materials(jsonb array of{ materialId, pct }),country_of_origin,sustainability_rating,certifications,embedding(vector(1536)),ai_tags,is_limited_edition,edition_size,edition_number,launch_date,discontinue_date,metadata. Indexed onsku,business_unit,status,brand_id,collection_id.freya_product_variants—product_id→freya_products(cascade delete),sku_suffix,full_sku(unique),size,color_name,color_pantone,color_hex,material_variant,weight_kg,price_adjustment,inventory_quantity,reserved_quantity,reorder_point,reorder_quantity,warehouse_location,barcode,is_active,image_urls.freya_collections—name,slug(unique),type,season,year,brand_id,theme,mood_board_urls,color_palette,style_count_target,launch_date,markets,price_range_min/price_range_max/currency,is_numbered,total_pieces,collaborator_name,collaborator_type,embedding(vector(1536)). Indexed onslug,(season, year),type,brand_id.freya_materials—code(unique),name,type, textile columns (fiber_composition,weave_type,weight_gsm,width_cm,thread_count,finish), leather columns (leather_type,tannage,thickness_mm), metal/gemstone columns (purity,carat,cut,clarity,color_grade), beauty-ingredient columns (inci_name,cas_number,ph_range_min/ph_range_max,max_use_pct,eu_restricted), quality and sustainability (grade,sustainability_score,certifications,origin_country,origin_region), supplier linkage (supplier_id→freya_suppliers,unit_of_measure,unit_cost,cost_currency,lead_time_days,minimum_order_quantity), storage (storage_conditions,shelf_life_months), and African-textile cultural metadata (cultural_origin,cultural_significance,pattern_name,is_heritage).freya_suppliers—code(unique),name,type, location columns, contact columns, capability columns (business_units,product_categories,capabilities, MOQ fields), performance ratings (quality_rating/delivery_rating/communication_rating/overall_rating,on_time_delivery_pct,defect_rate_pct,average_lead_time_days),certifications(jsonb array of{ name, body, expiry, verified }),is_verified,is_active,payment_terms_days,preferred_currency.freya_artisans—code(unique),name,craft_type, location columns,years_experience,specializations,certifications,portfolio_urls, capacity columns (monthly_capacity_units,typical_lead_time_days,day_rate_amount/day_rate_currency), cooperative columns,is_certified_fair_trade, ratings,bio,heritage_story.freya_manufacturing_orders—order_number(unique),type,business_unit,status(defaultplanned),priority, product linkage (product_id,variant_id,collection_id), production columns (facility_id,supplier_id,artisan_id,quantity,batch_size,quantity_completed,quantity_rejected,yield_pct),bom(jsonb), scheduling timestamps (planned_start_date,actual_start_date,target_completion_date,actual_completion_date), cost columns,labor_hours,quality_standard,quality_result, androuting(jsonb array of{ step, operation, workstation, durationMin, completedAt? }).freya_customers—email(unique), name/phone columns,date_of_birth,gender,market,segment(defaultnew),loyalty_tier(defaultbronze),loyalty_points,lifetime_points, diaspora columns (is_diaspora,origin_country,diaspora_country), financial columns (total_spend_ghs,order_count,average_order_value_ghs,last_purchase_at), preference columns (preferred_language,preferred_currency,preferred_categories,preferred_sizes,preferred_colors,preferred_brands,preferred_price_range,preferred_communication), VIP columns, body-measurement columns (measurements,hair_type,skin_type,fitzpatrick_scale),preference_embedding(vector(1536)), and consent columns (marketing_consent,data_processing_consent,consents_updated_at).freya_retail_locations—code(unique),name,type,brand_id, location/geo columns, lease columns, operations columns (opening_hours,staff_count,pos_terminal_count, manager contact), KPI columns (monthly_revenue_target_ghs,avg_daily_footfall,conversion_rate_pct,nps_score),business_units, and facility flags (has_fitting_room,has_vip_lounge,has_alteration_service,has_fragrance_bar).freya_orders—order_number(unique),customer_id→freya_customers,channel,market,status(defaultpending),lines(jsonb array of order-line objects),shipping_address/billing_address(jsonb), pricing columns (subtotal,shipping_cost,discount_amount,tax_amount,total,currency), payment columns (payment_method,payment_reference,payment_status,paid_at), shipping columns (shipping_method_id,carrier,tracking_number,estimated_delivery,delivered_at), promotion columns (promo_code,loyalty_points_earned,loyalty_points_redeemed,gift_message,gift_wrap), andretail_location_id→freya_retail_locationsfor click-and-collect.freya_carts—session_id(unique),customer_id,market,currency,lines(jsonb),promo_code,discount_amount,total_items,subtotal,expires_at.freya_wishlists—customer_id→freya_customers(cascade),name,is_public,share_token,items(jsonb).freya_virtual_tryon_sessions—customer_id,session_token(unique),product_id,variant_id, input columns (body_photo_urlephemeral — deleted after the session to satisfy privacy requirements,measurements_used), output columns (result_image_url,result_video_url,fit_assessment,recommended_size), feedback columns (customer_rating,added_to_cart,purchased), technical columns (ar_engine,processing_time_ms),expires_at.freya_brands—code(unique),name,parent_brand_id(self-referential), positioning columns (tier,tagline,heritage_story,founding_year,founded_in), identity columns (colors, fonts,logo_url,brand_book_url), target-market columns, social-media handles, and metrics (brand_equity_score,nps_score,social_followers).freya_brand_campaigns—brand_id→freya_brands,name,type,channels,markets, date columns, budget columns, KPI columns (target/actual impressions, conversions, revenue,roas), content columns (creative_assets,hashtags,influencer_ids),status.freya_influencer_partnerships—brand_id→freya_brands, influencer columns,platform,handle,followers,engagement_rate_pct,niche,tier,market, contract columns,fee_per_post/fee_currency,deliverables(jsonb),performance(jsonb),status.freya_quality_inspections—inspection_number(unique),type,manufacturing_order_id→freya_manufacturing_orders,batch_id,product_id,supplier_id, inspector columns, AQL sampling columns (lot_size,sample_size,aql_level,aql_criticaldefault 0,aql_majordefault 2.5,aql_minordefault 4.0), result columns (samples_inspected,defects_found,critical_defects,major_defects,minor_defects,defect_rate_pct,defect_details,result),test_results(jsonb),gmp_checks(jsonb — cosmetics GMP),corrective_actions(jsonb),retest_required,retest_date,certificate_url.freya_academy_students—student_number(unique),email(unique), name/contact columns,status(defaultenrolled), enrollment/graduation dates,programme,specialization,cohort,scholarship_type,tuition_paid,gpa,portfolio_url,certifications_earned(jsonb), employment columns.freya_academy_courses—code(unique),title,programme,level(100–400),credits,duration_weeks,description,learning_outcomes,prerequisites,instructor_id,materials_required,max_enrollment.freya_academy_enrollments—student_id→freya_academy_students(cascade),course_id→freya_academy_courses,academic_year,semester,grade,grade_letter,attendance_pct,status,completed_at.freya_formulations—code+version(unique pair),name,business_unit,category,subcategory,product_type,ingredients(jsonb array of INCI ingredient objects),total_batch_size_kg, physical-chemical specs (ph_min/ph_max, viscosity,density_g_ml, color/odor/appearance specs), safety columns (preservative_system,spf_value,is_allergen_free,allergens_present,eu_compliant,ghana_fda_approved,nafdac_approved), stability columns (shelf_life_months,storage_conditions,stability_results), fragrance-note columns (fragrance_family,top_notes,middle_notes,base_notes),efficacy_claims(jsonb),cost_per_kg/cost_currency,status,is_approved,approved_by,approved_at.freya_trend_signals—source,source_id,source_url, classification columns (business_unit,category,trend_name,tags), cultural columns (cultural_context,markets), metric columns (engagement_count,view_count,share_count,sentiment_score,virality_score,trend_velocity), AI-analysis columns (summary,design_recommendations,color_palette,material_suggestions),content_embedding(vector(1536)), lifecycle flags (is_emerging,is_mainstream,is_declining),peak_prediction_date,captured_at.freya_financial_records—period_year+period_month+business_unit+market(unique tuple),retail_location_id, revenue columns (gross_revenue_ghs,net_revenue_ghs,returns_amount_ghs,discount_amount_ghs), COGS columns (cogs_ghs,material_cost_ghs,labor_cost_ghs,overhead_cost_ghs), margin columns (gross_margin_ghs,gross_margin_pct), opex columns, EBITDA columns, volume columns (units_sold,transactions,average_transaction_value_ghs), inventory columns (inventory_value_ghs,inventory_turnover,days_inventory_outstanding), and accounts columns.freya_inventory_valuations—valuation_date,business_unit,product_id→freya_products,variant_id,quantity_on_hand,unit_cost_ghs,total_value_ghs,valuation_method(defaultFIFO),location_id.
Schema Indexes and Partitioning Notes#
Every table declares targeted B-tree indexes. Unique indexes enforce business
keys: freya_products.sku, freya_product_variants.full_sku,
freya_collections.slug, freya_materials.code, freya_suppliers.code,
freya_artisans.code, freya_manufacturing_orders.order_number,
freya_customers.email, freya_retail_locations.code,
freya_orders.order_number, freya_carts.session_id,
freya_virtual_tryon_sessions.session_token, freya_brands.code,
freya_quality_inspections.inspection_number,
freya_academy_students.student_number and email,
freya_academy_courses.code, the (code, version) pair on
freya_formulations, and the
(period_year, period_month, business_unit, market) tuple on
freya_financial_records. Query-pattern indexes cover status, business-unit,
foreign-key, and time-range filters (for example freya_orders is indexed on
customer_id, status, market, and created_at; freya_trend_signals on
source, business_unit, virality_score, captured_at, and is_emerging).
The five vector(1536) columns (freya_products.embedding,
freya_collections.embedding, freya_customers.preference_embedding,
freya_trend_signals.content_embedding) support pgvector similarity search for
catalog, collection, recommendation, and trend-clustering queries.
Connection Pooling (connection.ts)#
buildFreyaDbPoolConfig(serviceRole, overrides) sizes the connection pool
differently per service role, reflecting the read/write intensity of each
service. It produces a FreyaDbPoolConfig as follows: ecommerce (max 10 with
PgBouncer / 20 direct, min 2), manufacturing (5/10, min 1), analytics (3/5,
min 1), admin (3/5, min 1), background (2/3, min 0). It reads
FREYA_DATABASE_URL (falling back to DATABASE_URL, then
postgresql://oshun:oshun_dev@localhost:5432/freya), sets a 30-second
statement_timeout, and toggles PgBouncer transaction mode when
FREYA_USE_PGBOUNCER is true. buildReadReplicaConfig routes
analytics/reporting reads to weighted replicas listed in
FREYA_DATABASE_REPLICA_URLS. buildPgBouncerUrl rewrites the port to
PGBOUNCER_PORT (default 6432) and disables prepared statements. The Drizzle
migration config (FREYA_DRIZZLE_CONFIG) points at schema.ts, outputs to
libs/freya/db/drizzle, dialect postgresql, with tablesFilter: ['freya_*'].
Redis Caching (redis-config.ts)#
Redis is central to Freya's real-time commerce behavior: inventory availability, cart state, and pricing are all read from Redis rather than Postgres on the hot path.
FREYA_REDIS_PREFIX is freya. FreyaRedisKeys builds namespaced keys for
inventory (freya:inv:{variantId}), product catalog, collection, customer
session/profile/loyalty, cart, exchange rates, per-market product price, store
KPIs and footfall, trend scores, API and checkout rate-limit counters,
virtual-try-on session, and distributed locks (freya:lock:inv:{variantId},
freya:lock:checkout:{orderId}).
FreyaRedisTTL defines TTLs in seconds: inventory 30, product 600, product
search 120, collection 3600, session 86400 (sliding), customer profile 900, cart
604800, exchange rates 900, product price 900, store KPI 300, trend score 3600,
trending-now 1800, rate limit 60, lock 10, try-on session 1800.
FreyaInvalidationPatterns defines SCAN-based bulk invalidation groups.
FreyaPubSubChannels defines the six Redis pub/sub channels used for
low-latency fan-out to connected clients: freya:pubsub:inventory,
freya:pubsub:order_status, freya:pubsub:price, freya:pubsub:store_kpi,
freya:pubsub:trend, freya:pubsub:cart. buildInventoryCacheEntry computes a
write-through InventoryCacheEntry whose available is
max(0, inventoryQty - reservedQty). buildFreyaRedisConfig reads
FREYA_REDIS_URL/REDIS_URL (default redis://localhost:6379).
Object Storage (s3-config.ts)#
Three MinIO/S3 buckets serve different asset types with different access and retention policies:
freya-design-assets— private, signed URLs only, versioned, with a 730-day Glacier transition for archived designs. Used for sketches, tech packs, patterns, mood boards, and CAD files.freya-product-imagery— public CDN-served, not versioned, 365-day expiration. Used for studio shots, lifestyle images, 360-degree frames, and AR.glbmodels.freya-manufacturing-docs— strictly private, versioned, retained for regulatory compliance. Used for GMP batch records, QC reports, QC photos, certificates, and formulation documents.
FreyaS3Keys defines object-key conventions per asset class.
FREYA_S3_SIGNED_URL_TTL sets signed-URL lifetimes per class.
buildFreyaS3Config reads FREYA_S3_ENDPOINT, FREYA_S3_REGION,
FREYA_S3_ACCESS_KEY, FREYA_S3_SECRET_KEY, and FREYA_CDN_BASE_URL, and
forces path-style addressing for MinIO.
Observability (observability.ts)#
FREYA_OTEL_CONFIG configures OpenTelemetry tracing. FREYA_PROMETHEUS_METRICS
defines the Prometheus metric catalog and FREYA_METRICS_CONFIG its scrape
settings. Structured logging uses FreyaLogEntry with LogLevel of debug,
info, warn, error, fatal. FREYA_CIRCUIT_BREAKERS defines per-service
circuit-breaker configs with a CircuitBreakerState of closed, open, or
half_open; shouldOpenCircuit and shouldCloseCircuit implement the
transition logic.
Reference Seed Data (seed.ts)#
seed.ts ships reference datasets used during development and testing rather
than transactional rows. It includes: FABRIC_REFERENCE (African textile types
with GSM ranges, fiber composition, cultural origin and significance, and
isHeritage flags — e.g. Ankara wax print, Kente cloth), ingredient INCI
references, GIA-standard gemstone grades, the African Pantone palette, and
per-market standard size charts.
API Surface: apps/freya/api#
@freya/api (apps/freya/api/src) exposes the Freya domain through REST,
GraphQL, gRPC, and WebSocket interfaces. Source modules: schemas.ts,
middleware.ts, product-routes.ts, order-routes.ts, customer-routes.ts,
other-routes.ts, graphql-schema.ts, websocket.ts, grpc-services.ts,
event-bus.ts, openapi-spec.ts.
REST Endpoints and Route Map#
The OpenAPI 3.1 spec (openapi-spec.ts) is the published REST contract, served
at /openapi.json. Base path /v1. FREYA_API_ROUTES enumerates the route
map. OpenAPI servers are https://api.freya.oshun.ai/v1 (production),
https://api.staging.freya.oshun.ai/v1 (staging), and
http://localhost:3500/v1 (local).
| Route group | Path | Notes |
|---|---|---|
| Health | /health |
GET, unauthenticated readiness check |
| Products | /v1/products |
GET list, POST create (bearer auth) |
| Products | /v1/products/{id} |
GET by ID |
| Orders | /v1/orders |
POST place order (bearer auth) |
| Orders | /v1/orders/{id} |
GET by ID (bearer auth) |
| Customers | /v1/customers |
POST register |
| Customers | /v1/customers/{id} |
GET profile (bearer auth) |
| Collections | /v1/collections |
Collection route group |
| Brands | /v1/brands |
Brand route group |
| Manufacturing | /v1/manufacturing |
Production-order route group |
| Quality | /v1/quality |
AQL/GMP inspection route group |
| Inventory | /v1/inventory |
Real-time inventory route group |
| Formulations | /v1/formulations |
Beauty/personal-care formulation route group |
| Academy | /v1/academy |
Student/course route group |
| Webhooks | /v1/webhooks/{paystack,stripe,flutterwave,shipping,social} |
API-key authenticated |
| GraphQL | /graphql |
GraphQL endpoint |
| WebSocket | /ws |
Real-time channel |
REST Authentication and Authorization (middleware.ts)#
Two security schemes are enforced. bearerAuth uses JWT for user-facing calls;
apiKey (the X-API-Key header) is used for service-to-service calls and
webhook validation.
UserRole is one of customer, associate, manager, admin.
authMiddleware validates a three-part bearer token, checks required claims
(userId, email, role), enforces expiresAt, and rejects unknown roles.
ROLE_PERMISSIONS defines what each role can do:
customer—products:read,orders:create,orders:read:own,customer:read:own,customer:update:own,loyalty:read:own,loyalty:redeem:own,cart:manage:own,wishlist:manage:own,reviews:create.associate—products:read,orders:read,inventory:read,customer:read,clienteling:manage,transactions:create,store:read.manager— addsproducts:write,orders:update,inventory:manage,reports:read,staff:read,store:manage,manufacturing:read,manufacturing:write,analytics:read.admin— wildcard*(full access).
rbacMiddleware enforces :own permissions with an ownership check: the
requesting user must match the resource owner. Rate limiting (RATE_LIMITS)
uses three buckets: api allows 100 requests/60 s, auth 10/60 s, webhooks
1000/60 s; rateLimitMiddleware returns retryAfterMs when a window is
exhausted.
REST Request/Response Schemas#
Two Zod schema sets exist. The API app's own schemas.ts backs the handler
logic directly. @freya/contracts holds the cross-service contract schemas
consumed by any other domain calling Freya.
apps/freya/api/src/schemas.ts defines, among others:
CreateProductSchema/UpdateProductSchema/SearchProductsSchema,
CreateOrderSchema (with paymentMethod of card/mobile_money/
bank_transfer and market of ghana/nigeria/uk/eu/us),
UpdateOrderStatusSchema, ProcessReturnSchema, ProcessRefundSchema,
RegisterCustomerSchema, UpdateProfileSchema, UpdatePreferencesSchema,
RedeemPointsSchema (points must be a positive multiple of 100),
CreateManufacturingOrderSchema (priority RUSH/STANDARD/DEFERRED),
ScheduleOrderSchema, UpdateBatchSchema, RecordQualityCheckSchema (defect
class CRITICAL/MAJOR/MINOR), ScheduleMaintenanceSchema,
RecordTransactionSchema, LookupInventorySchema, RequestTransferSchema,
CreateCampaignSchema, AddInfluencerSchema, TrackCampaignMetricsSchema,
CreateFormulationSchema, AddIngredientSchema, ScheduleStabilityTestSchema,
GetTrendReportSchema, GetFinancialReportSchema, and webhook schemas
(PaystackWebhookSchema, StripeWebhookSchema, ShippingUpdateSchema,
SocialCommerceWebhookSchema).
@freya/contracts (libs/contracts/freya/src) defines four schema modules:
product-schemas.ts—ProductStatusSchema(draft,active,archived,out_of_stock,discontinued),ProductCategorySchema(fashion,textiles,beauty,skincare,haircare,fragrance,jewelry,footwear,eyewear,accessories,home_decor,luggage,personal_care,detergent),MarketSchema(GH,NG,KE,ZA,UK,US,EU,CA,AU,GLOBAL),PriceSchema,ProductVariantSchema,CreateProductRequestSchema,UpdateProductRequestSchema,ProductSearchRequestSchema,ProductResponseSchema.order-schemas.ts—OrderStatusSchema(pending,confirmed,processing,shipped,delivered,cancelled,refunded,return_requested,returned),ShippingAddressSchema,OrderLineSchema,CreateOrderRequestSchema,UpdateOrderStatusRequestSchema,OrderResponseSchema.customer-schemas.ts—CustomerSegmentSchema(vip,premium,regular,new,diaspora,wholesale,corporate),LoyaltyTierSchema(bronze,silver,gold,platinum,diamond),RegisterCustomerRequestSchema,UpdateCustomerRequestSchema,CustomerPreferencesSchema,CustomerResponseSchema.manufacturing-schemas.ts—ManufacturingOrderStatusSchema(planned,in_progress,quality_check,completed,on_hold,cancelled),BusinessUnitSchema(eighteen values matchingfreya_business_unit),CreateManufacturingOrderRequestSchema,QualityInspectionRequestSchema,ManufacturingOrderResponseSchema.
REST Order State Machine (order-routes.ts)#
The customer-order handler enforces a strict status state machine for orders flowing through the REST API. This is the public-API order lifecycle, separate from the ecommerce DTC fulfillment machine and the factory-floor machine.
OrderStatus is PLACED, CONFIRMED, SHIPPED, DELIVERED, RETURNED,
CANCELLED. Legal transitions:
| From | To |
|---|---|
PLACED |
CONFIRMED, CANCELLED |
CONFIRMED |
SHIPPED, CANCELLED |
SHIPPED |
DELIVERED |
DELIVERED |
RETURNED |
RETURNED |
— (terminal) |
CANCELLED |
— (terminal) |
handleProcessReturn rejects returns on any order not in DELIVERED.
handleProcessRefund rejects a refund amount exceeding the order total.
computeOrderTotals applies 15% tax and free domestic shipping for
Ghana/Nigeria orders ≥ GHS 500 (otherwise GHS 30 domestic, GHS 150
international).
GraphQL API (graphql-schema.ts)#
FREYA_GRAPHQL_TYPEDEFS is a schema-first SDL definition. It mirrors the REST
surface but adds real-time subscription and connection-based pagination.
Enums: BusinessUnit (eighteen values), ProductStatus (eight values matching
freya_product_status), Season, Market, OrderStatus, LoyaltyTier.
Object types include Product, ProductVariant, Collection, Brand,
InventoryLevel, Customer, Order, OrderLine, TrendSignal, Relay-style
connection/edge types, and PageInfo. Queries cover product/collection/brand
lookup and listing, inventory levels, customer lookup, order lookup, and
trending signals. Mutations cover createProduct, updateProductStatus,
createOrder, updateOrderStatus, cancelOrder, registerCustomer,
updateCustomerProfile, addLoyaltyPoints, cart operations (addToCart,
removeFromCart, updateCartQuantity), and inventory operations
(reserveInventory, releaseInventory). Subscriptions are inventoryUpdated,
orderStatusChanged, trendSignalReceived, and storeKpiUpdated.
encodeCursor/decodeCursor implement base64 offset cursors.
gRPC Services (grpc-services.ts)#
gRPC is used for the five internal high-throughput service calls that need lower
overhead than HTTP/REST. FREYA_GRPC_PACKAGE is freya.internal, version v1.
The five services are defined as GrpcServiceDefinition records:
InventoryService—CheckInventory,BatchCheckInventory,ReserveInventory(TTL-based, idempotent),ReleaseReservation,StreamInventoryUpdates(server streaming).ManufacturingService—GetManufacturingOrder,ListManufacturingOrders,UpdateManufacturingStatus,StreamProductionEvents(server streaming).QualityService—EvaluateQualityGate(AQL-based gate evaluation).PricingService—GetPricing(final price with promotions, loyalty, market pricing).CustomerService—GetCustomerProfile,AdjustLoyaltyPoints(transactional earn/redeem).
generateProtoStub scaffolds a proto3 service definition from each
GrpcServiceDefinition. ReleaseReservationRequest.reason is one of
order_confirmed, order_cancelled, expired.
QualityGateResponse.nextAction is one of release, rework, scrap,
retest.
WebSocket API (websocket.ts)#
The WebSocket server at /ws carries three categories of real-time message:
inventory updates for live stock counts, auction bidding for limited-edition
drops, and collaborative design sessions in the studio app.
WsMessageType enumerates subscribe, unsubscribe, inventory_update,
order_status, bid_placed, auction_ended, price_alert,
collaboration_join, collaboration_cursor, collaboration_change,
store_kpi, trend_signal, error, ping, pong. WsChannel is one of
inventory, orders, auctions, collaboration, store_kpis, trends.
Typed payloads exist for each message type: InventoryUpdatePayload,
OrderStatusPayload, BidPayload, AuctionEndedPayload,
CollaborationCursorPayload, CollaborationChangePayload, StoreKpiPayload,
TrendSignalPayload. WS_CONFIG sets a 30-second ping interval, 10-second pong
timeout, 20 subscriptions per connection, 64 KB max message size, and a
100-message backpressure queue. buildReservationResult produces an
InventoryReservationResult whose failureReason is one of
insufficient_stock, already_reserved, product_discontinued.
Domain Events (event-bus.ts)#
Freya domain events follow the CloudEvents 1.0 envelope. The DomainEvent<T>
type carries: specversion, id, source, type, datacontenttype, optional
dataschema, subject, time, data, optional correlationId,
businessUnit, market. Events are published to Kafka topics and consumed by
subscribing services inside and outside the Freya domain.
FreyaEventType enumerates the full event vocabulary, organized by family:
- Product —
freya.product.created,freya.product.updated,freya.product.status_changed,freya.product.discontinued. - Inventory —
freya.inventory.stocked,freya.inventory.reserved,freya.inventory.released,freya.inventory.depleted,freya.inventory.reorder_triggered. - Orders —
freya.order.placed,freya.order.confirmed,freya.order.processing,freya.order.shipped,freya.order.delivered,freya.order.cancelled,freya.order.refunded,freya.order.return_requested. - Manufacturing —
freya.manufacturing.order_created,freya.manufacturing.started,freya.manufacturing.batch_completed,freya.manufacturing.quality_passed,freya.manufacturing.quality_failed,freya.manufacturing.completed,freya.manufacturing.cancelled. - Quality —
freya.quality.inspection_scheduled,freya.quality.inspection_completed,freya.quality.corrective_action_required. - Customers —
freya.customer.registered,freya.customer.segment_changed,freya.customer.loyalty_tier_changed,freya.customer.vip_granted,freya.customer.points_earned,freya.customer.points_redeemed. - Trends —
freya.trend.signal_detected,freya.trend.reached_mainstream,freya.trend.declining. - Collections —
freya.collection.created,freya.collection.launched,freya.collection.sold_out. - Academy —
freya.academy.student_enrolled,freya.academy.student_graduated,freya.academy.certification_issued. - Formulations —
freya.formulation.approved,freya.formulation.rejected,freya.formulation.batch_released. - Retail —
freya.retail.store_opened,freya.retail.daily_close,freya.retail.kpi_updated. - Payments —
freya.payment.succeeded,freya.payment.failed,freya.payment.refunded.
FREYA_EVENT_TOPICS maps event types to six Kafka topics: freya.orders,
freya.inventory, freya.production, freya.quality, freya.customers,
freya.trends; resolveEventTopic falls back to freya.misc for unmapped
types. FREYA_DLQ_TOPIC is freya.dlq.
Defined payload interfaces capture the data that crosses service boundaries:
ProductCreatedEventData, OrderPlacedEventData (includes orderId,
orderNumber, customerId, market, channel, currency, totalAmount,
lineCount, lines, paymentReference), OrderShippedEventData,
InventoryReservedEventData (includes reservationToken, expiresAt),
InventoryDepletedEventData, ManufacturingBatchCompletedEventData,
QualityInspectionCompletedEventData (result of
passed/failed/conditional_pass/pending_retest, nextAction of
release/rework/scrap/retest), CustomerLoyaltyTierChangedEventData,
TrendSignalDetectedEventData, FormulationApprovedEventData.
buildFreyaEventBusConfig reads FREYA_KAFKA_BROKERS/KAFKA_BROKERS (default
localhost:9092), defaults producer acks to -1 (all replicas — important for
orders and payments), and uses snappy compression. FREYA_CONSUMER_CONFIGS
defines consumer groups per service role: freya-ecommerce consumes
freya.orders/freya.inventory/freya.customers; freya-manufacturing
consumes freya.orders/freya.production/freya.quality; freya-retail
consumes freya.inventory/freya.customers/freya.trends;
freya-trend-worker consumes freya.trends.
Capability Libraries#
Each capability library is deterministic, domain-specific business logic — not
generic CRUD. Libraries depend on @freya/core for shared types and never on
each other. State machines in every library are enforced with explicit
transition tables that throw on illegal transitions.
@freya/fashion — Apparel Design Pipeline#
Source modules: design-pipeline.ts, collection-planner.ts,
size-grading.ts, trend-forecasting.ts, production-scheduler.ts,
african-print-library.ts.
Design pipeline state machine (DesignPipeline). Every style moves through
a controlled set of stages, each of which has defined entry requirements.
DesignStage is concept, mood_board, sketch, pattern, prototype,
sample, production, discontinued. transitionTo throws on any unlisted
transition and appends a timestamped entry to history.
| From | To |
|---|---|
concept |
mood_board, discontinued |
mood_board |
sketch, concept, discontinued |
sketch |
pattern, mood_board, discontinued |
pattern |
prototype, sketch, discontinued |
prototype |
sample, pattern, discontinued |
sample |
production, prototype, discontinued |
production |
discontinued |
discontinued |
— (terminal) |
ApprovalStatus (used by sketches and design approvals) is pending,
approved, rejected, revision_required.
Other classes in this library: ConceptBoardManager, SketchManager (versioned
sketches), PatternMaker (default 1.5 cm seam allowance, marker utilization
estimation), PrototypingTracker (capped at MAX_REVISION_CYCLES = 5),
TechPackGenerator (emits a TechPack with a six-row XS–XXL measurements
table, BOM, construction details, and labeling specs; validate checks required
fields), DesignApprovalWorkflow (multi-stakeholder sign-off — required roles
designer, merchandiser, qa, director; overall status derived from all
sign-offs), DesignAssetManager (AssetType of sketch/photo/3d/flat),
and DesignCostEstimator (30% overhead rate, SMV-based labor costing).
Collection planning. CollectionStatus is concept, design,
production, launched, archived. SEASON_CALENDAR defines per-season show
months, delivery months, and milestone offsets for SS, FW, Resort,
PreFall, and Capsule. CapsuleCollectionBuilder enforces MAX_STYLES = 12.
CollectionBudgetPlanner applies a 2.2× wholesale markup and 2.4×
retail-on-wholesale markup, and enforces a minimum 60% gross margin
(marginCompliant). CollectionPresentationBuilder requires 6–12 looks.
@freya/textiles — Dyeing, Printing, Finishing#
Source modules: dye-management.ts, print-operations.ts,
finishing-operations.ts, vertical-integration.ts.
dye-management.ts models dye recipes (DyeClass of reactive, acid,
disperse, vat, direct), a dye-process state machine (DyePhase of
loading, heating, dyeing, rinsing, unloading), color matching against
Lab color values, dye-consistency SPC control limits, water-usage optimization,
chemical inventory with HazardClass 1–9, African natural-dye formulation
(NaturalDyeFormulator), and effluent compliance monitoring
(EffluentParameter of COD, BOD, pH, color_ADMI, TDS).
print-operations.ts models a wax print state machine, digital/screen/block
printing, print design preparation, and print costing. finishing-operations.ts
models finishing processes (sanforizing, calendering, mercerizing, softening,
anti-shrink), DWR water repellency (DWRChemistry from C8_PFAS through
C0_bio), wrinkle resistance, a fabric-testing lab, and a finishing quality
gate.
vertical-integration.ts models make-vs-buy analysis, spinning/weaving/knitting
operations, capacity planning, textile cost modeling, waste reduction, Kente
weave preservation (KENTE_COLOR_MEANINGS), and a sustainability scorecard.
@freya/beauty — Skincare, Cosmetics, Fragrance, Haircare#
Source modules: skincare-formulation.ts, cosmetics-development.ts,
fragrance-development.ts, haircare-development.ts,
personal-care-detergent.ts, stability-regulatory.ts.
skincare-formulation.ts models a formulation lifecycle, shea-butter and
cocoa-butter grade management (SheaButterGrade, CocoaButterType), an African
botanical library, a formulation incompatibility checker
(IncompatibilitySeverity of mild/moderate/severe), emulsion HLB
calculation (EmulsionType W/O/O/W), preservative-system design, an SPF
calculator over a UV-filter library, and batch costing.
cosmetics-development.ts models a cosmetics development pipeline with
STAGE_DELIVERABLES, shade-range design (Undertone of
cool/neutral/warm/olive), lip and eye product formulation, packaging
design, product naming, and launch planning.
fragrance-development.ts models the fragrance pyramid (FragranceNoteClass
top/heart/base with evaporation profiles), an African scents library, perfume
concentration specs (PerfumeConcentration), and fragrance blending.
haircare-development.ts and personal-care-detergent.ts cover Afro-textured
haircare and personal-care/detergent formulation respectively.
stability-regulatory.ts covers stability testing protocols and regulatory
submission logic across Ghana FDA, NAFDAC, EU SCCS, and US FDA.
@freya/ecommerce — Catalog, Cart, Checkout, Diaspora DTC#
Source modules: catalog-inventory.ts, social-personalization.ts,
diaspora-commerce.ts.
Ecommerce order state machine (catalog-inventory.ts). This is the DTC
fulfillment lifecycle, separate from the REST API's customer-order machine.
OrderStatus has fourteen values: placed, payment_confirmed, processing,
picked, packed, shipped, out_for_delivery, delivered,
return_requested, return_approved, returned, refund_processing,
refunded, cancelled.
Other enums and classes in this module: PaymentGateway (paystack,
flutterwave, stripe), PaymentMethod (includes mtn_momo, vodafone_cash,
bank_card, bank_transfer, ussd, card, apple_pay, google_pay),
ShippingCarrier (DHL, FedEx, UPS), CheckoutStep (cart_review,
address, shipping, payment, confirmation). Classes include
ProductCatalogService, CartManager, CheckoutOrchestrator,
PaymentProcessor, OrderManagementService, InventoryService (over a fixed
WAREHOUSES set), WishlistService, ReviewService, and SearchEngine.
diaspora-commerce.ts models diaspora markets (DiasporaCountry),
multi-currency management, international shipping calculation, customs document
generation, diaspora pricing strategy, localized content (Language en/fr),
and international returns. social-personalization.ts models social commerce, a
product recommendation engine, customer segmentation (BehavioralSegment of
vip, loyal, at_risk, new, dormant, one_time), email-marketing
automation (EmailFlowType), a subscription-box manager (SubscriptionTier of
essentials/luxe/heritage), abandoned-cart recovery, a customer
lifetime-value model, a loyalty-program engine (LoyaltyTierName from bronze
to obsidian), and virtual try-on integration (TryOnProductType).
@freya/manufacturing — Production Execution#
Source modules: cosmetics-manufacturing.ts, textile-manufacturing.ts,
assembly-manufacturing.ts, cross-manufacturing.ts.
cosmetics-manufacturing.ts models a cosmetics manufacturing stage machine,
clean-room management (CleanRoomISO ISO7/ISO8), BatchScale of lab,
pilot, commercial, mixing-process control, filling lines (FillingLineType
of tube/jar/pump_bottle), batch records, in-process quality testing, and a
detergent manufacturing line (DetergentProductionMethod of spray_drying,
agglomeration, liquid_mixing).
cross-manufacturing.ts models machine utilization (OEE — OEELossCategory),
production cost analysis, lean manufacturing (MudaType waste categories),
capacity planning, equipment maintenance (MaintenanceType of
preventive/predictive/corrective), manufacturing compliance
(ComplianceStandard of ISO9001, ISO22716, ISO14001, ISO45001,
OHSAS18001), waste management, and energy management (EnergySource of
grid/solar/generator).
textile-manufacturing.ts models textile production lines
(ProductionLineStatus of idle, setup, running, maintenance,
breakdown), loom scheduling (LoomType of shuttle/rapier/air_jet),
dye-house planning, textile waste tracking, and maintenance scheduling.
assembly-manufacturing.ts models per-product-type assembly stage machines for
watches, jewelry, eyewear, footwear, and leather goods, plus a component
inventory manager.
@freya/retail — Store Operations and Clienteling#
Source modules: store-operations.ts, customer-experience.ts,
portfolio-management.ts.
store-operations.ts models a fixed StoreId set (accra_osu, accra_mall,
kumasi_garden_city, lagos_victoria_island), opening/closing checklists
(ChecklistStage, ChecklistItemStatus of pending/in_progress/
completed/issue), visual merchandising by StoreZone, store inventory
management (StockCategory of fashion/beauty/jewelry), sales analytics,
staff scheduling and performance tracking, POS integration (PaymentMethod of
cash/card/MoMo), customer-traffic analysis, and store maintenance
(MaintenanceUrgency of routine/urgent/emergency).
customer-experience.ts models in-store personalization, a clienteling tool,
VIP experience management (VIPService), in-store try-on tracking
(TryOnOutcome of purchased/not_purchased/size_exchange), and customer
feedback (NPSClassification of promoter/passive/detractor).
@freya/brand — Brand Architecture and Storytelling#
Source modules: brand-architecture.ts, heritage-storytelling.ts,
digital-presence.ts.
brand-architecture.ts models brand relationship structures
(BrandRelationshipType of master/endorsed/sub), a brand positioning map,
brand-guideline management, brand-equity measurement, sub-brand creation,
brand-consistency auditing, brand-extension evaluation, and co-branding
opportunity identification.
heritage-storytelling.ts models a heritage story engine, artisan story
capture, a cultural calendar manager, a provenance story builder
(NarrativeComponent, LuxuryPillar), and luxury positioning strategy.
digital-presence.ts models social-media monitoring (SocialChannel),
brand-sentiment analysis, influencer management (InfluencerTier of
nano/micro/macro/mega), PR coverage tracking, diaspora brand perception
(DiasporaMarketKey), content-calendar planning, UGC curation, and competitor
brand tracking.
@freya/academy — Curriculum and Certification#
Source modules: curriculum.ts, curriculum-internals.ts, course-management
(academy-operations.ts), student-management.ts.
CourseLevel is certificate, diploma, degree. BloomsTaxonomyLevel
models the cognitive taxonomy used for learning outcome design. Classes include
CurriculumDesigner, CourseManager, ModuleBuilder, and three specialized
curriculum builders: AfricanFashionCurriculum, SustainableFashionCurriculum,
BusinessFashionCurriculum. student-management.ts manages student records and
progression.
@freya/jewelry — Ethical Gold Jewelry#
Source modules: jewelry-production.ts, gold-management.ts,
craft-preservation.ts. This library focuses heavily on provenance: it covers
gold sourcing and management with full chain-of-custody tracking, jewelry
production processes, hallmarking, and craft preservation with artisan heritage
records.
@freya/market-intel — Trend and Competitive Intelligence#
Source modules: trend-monitoring.ts, competitive-intelligence.ts,
market-research.ts. Models trend monitoring (ingesting runway, social, and
sales-data signals), competitive intelligence (CompetitorMove), and market
research. Outputs feed into @freya/financials and @freya/brand.
@freya/financials — Unit Economics and Investment#
Source modules: unit-economics.ts, financial-planning.ts,
startup-investment.ts. FreyaBusinessUnit enumerates the financed business
units. InvestmentScale is pilot, standard, flagship. Classes include
StartupCostModeler, PhaseInvestmentPlanner, FundingStructureOptimizer,
EquipmentCapexPlanner, FacilityInvestmentModeler (FacilityType,
Location), and ROIProjector. DepreciationMethod is straight_line or
declining_balance.
@freya/connectors — Cross-Domain Integration#
Source modules: asase-connectors.ts, brigid-connectors.ts,
cybele-connectors.ts, saraswati-connectors.ts, maat-connectors.ts. This
library is the sole point where Freya's shapes are translated to other domains'
contracts, keeping all cross-domain coupling in one place.
- Asase (agriculture, task 57.14.1) —
SheaButterSupplyChain,CocoaButterProcurement,NaturalIngredientTraceability,CottonSupplyChain,IngredientQualitySync,FairTradeCertification. - Brigid (manufacturing automation, 57.14.2) —
TextileAutomation,CosmeticsPackagingAutomation,QualityVisionSystem,SmartPackaging,PredictiveMaintenanceSync. - Cybele (construction, 57.14.3) —
FlagshipStoreDesign,RetailSpacePlanning,FactoryConstruction,InteriorTextileSupply. - Saraswati (logistics, 57.14.4) —
EcommerceLogistics,IoTRetailSensors,SmartWarehouse,EVDeliveryFleet. - Maat (strategic intelligence, 57.14.5) —
FreyaDashboardSync,BrandAnalyticsFeed,FinancialConsolidation,MarketIntelligenceFeed.
@freya/sota — State-of-the-Art Enhancements#
Source modules: ai-design.ts, ai-analytics.ts, computer-vision.ts,
nlp.ts, blockchain-auth.ts, virtual-tryon.ts. This library houses the
Phase 57 state-of-the-art layer: AI-assisted design and generative collection
ideation, AI analytics, computer-vision quality control, NLP, blockchain-based
authenticity verification, and virtual try-on. Each is delivered as an opt-in
enrichment over the deterministic capability libraries — the business logic does
not depend on them and remains testable in isolation.
Single-Module Business-Unit Libraries#
Eleven libraries each ship a single src/index.ts module, owning their
business-unit logic: @freya/watches, @freya/perfumes,
@freya/bridal-events, @freya/hair-care, @freya/home-decor,
@freya/footwear, @freya/eyewear, @freya/luggage-leather,
@freya/personal-care, @freya/cleaning-products, @freya/textile-finishing.
(@freya/textile-finishing's index.ts models textile production lines, loom
scheduling, dye-house planning, waste tracking, energy monitoring, and
maintenance scheduling.)
Applications#
Five applications under apps/freya/* compose user workflows over the
capability libraries. Each ships a thin set of view/orchestration modules.
Applications depend on capability libraries but not on each other; cross-app
coordination goes through the API service and the event bus.
apps/freya/api— documented in full in the API Surface section above.apps/freya/studio— design and brand studio. Source modules:trend-board.ts,collection-dashboard.ts,design-workspace.ts,design-approval-board.ts,tech-pack-editor.ts,textile-library.ts,color-palette-studio.ts.apps/freya/shop— DTC storefront. Source modules:product-listing.ts,product-detail.ts,shopping-cart.ts,checkout-flow.ts,customer-account.ts,subscription-box.ts,virtual-tryon.ts.apps/freya/retail— retail-operations app. Source modules:store-dashboard.ts,clienteling-app.ts,inventory-lookup.ts,staff-performance.ts,visual-merchandising.ts.apps/freya/manufacturing— factory-floor app. Source modules:order-management.ts,production-dashboard.ts,batch-record-manager.ts,quality-inspection.ts,equipment-dashboard.ts,waste-reporting.ts.
Manufacturing-App Order State Machine (order-management.ts)#
The factory-floor app enforces its own strict linear state machine over
manufacturing orders. This is separate from the supply-chain OrderStatus in
@freya/core and the ecommerce DTC machine in @freya/ecommerce.
OrderStatus is DRAFT, SCHEDULED, IN_PROGRESS, QC, COMPLETE,
SHIPPED. OrderPriority is RUSH, STANDARD, DEFERRED.
| Method | Requires status | Sets status |
|---|---|---|
createOrder |
— | DRAFT |
scheduleOrder |
DRAFT |
SCHEDULED |
startProduction |
SCHEDULED |
IN_PROGRESS |
moveToQC |
IN_PROGRESS |
QC |
completeOrder |
QC |
COMPLETE |
shipOrder |
COMPLETE |
SHIPPED |
assertStatus throws if an order is not in the expected status, preventing
out-of-sequence transitions. A RUSH priority applies the
RUSH_PREMIUM_MULTIPLIER of 2.0 to the order's total cost.
Configuration and Environment Inputs#
The following environment variables control all infrastructure connections. Every variable has a fallback so the system runs locally without extra configuration.
| Variable | Consumed by | Default |
|---|---|---|
FREYA_DATABASE_URL / DATABASE_URL |
connection.ts, FREYA_DRIZZLE_CONFIG |
postgresql://oshun:oshun_dev@localhost:5432/freya |
FREYA_DATABASE_REPLICA_URLS |
buildReadReplicaConfig |
empty (no replicas) |
FREYA_USE_PGBOUNCER |
buildFreyaDbPoolConfig |
false |
PGBOUNCER_PORT |
buildPgBouncerUrl |
6432 |
FREYA_REDIS_URL / REDIS_URL |
buildFreyaRedisConfig |
redis://localhost:6379 |
FREYA_S3_ENDPOINT / S3_ENDPOINT |
buildFreyaS3Config |
http://localhost:9000 |
FREYA_S3_REGION / S3_REGION |
buildFreyaS3Config |
us-east-1 |
FREYA_S3_ACCESS_KEY / S3_ACCESS_KEY |
buildFreyaS3Config |
minioadmin |
FREYA_S3_SECRET_KEY / S3_SECRET_KEY |
buildFreyaS3Config |
minioadmin |
FREYA_CDN_BASE_URL |
buildFreyaS3Config |
http://localhost:9000/freya-product-imagery |
FREYA_S3_BUCKET_DESIGN / _PRODUCTS / _MANUFACTURING |
FREYA_S3_BUCKETS |
freya-design-assets / freya-product-imagery / freya-manufacturing-docs |
FREYA_KAFKA_BROKERS / KAFKA_BROKERS |
buildFreyaEventBusConfig |
localhost:9092 |
FREYA_KAFKA_CLIENT_ID |
buildFreyaEventBusConfig |
freya-producer |
FREYA_KAFKA_GROUP_ID |
event-bus producer/consumer config | freya-producers |
FREYA_KAFKA_GROUP_ID_ORDERS / _MANUFACTURING |
FREYA_CONSUMER_CONFIGS |
freya-orders-consumer / freya-manufacturing-consumer |
Requirements and Invariants#
These six requirements are enforced by code or mandated by features.md for any
change touching the relevant data. They are not optional — violating any of them
can result in regulatory exposure, data loss, or financial errors.
-
Provenance and certification evidence.
Material,Supplier,Artisan, andfreya_materialsrecords retain source country/region andcertifications. Jewelry and gold provenance records retain full source and certification evidence permanently.freya_quality_inspectionsretainscertificate_url, defect detail, and corrective actions. -
Idempotent commerce. Inventory reservation is TTL-based and idempotent (gRPC
ReserveInventoryaccepts areservationTokenfor idempotent checks;InventoryReservedEventDatacarries areservationToken). Order and inventory updates must not double-create or double-decrement on a retried webhook or sync event. Cart and inventory state is held in Redis with distributed locks (freya:lock:inv:{variantId},freya:lock:checkout:{orderId}). -
Beauty audit trails and formulation versioning.
Formulationcarries aversion;freya_formulationsuses a(code, version)unique pair so a formulation change creates a new version rather than mutating the prior one. Stability and regulatory records are append-only evidence. Beauty productefficacy_claimsare stored with their evidence type and study reference. -
Privacy and role-based access.
freya_customerscarriesmarketing_consent,data_processing_consent, andconsents_updated_at.freya_virtual_tryon_sessions.body_photo_urlis ephemeral and deleted after the session. The API enforcesUserRole-based RBAC with:ownownership checks (middleware.ts). -
State-machine integrity. Order and design state machines reject illegal transitions: the REST customer-order machine, the ecommerce DTC fulfillment machine, the manufacturing-app
OrderManagementmachine, the fashionDesignPipeline, and the various per-product-type assembly machines all use explicit transition tables and throw on violation. -
Quality gating. A failed AQL inspection (
evaluateQualityResultreturningfail) blocks order release;QualityGateResponse.nextActiondrives therelease/rework/scrap/retestdecision.
Domain Boundaries#
Freya owns luxury-goods business operations and product supply. It does not
own personal consumer styling, virtual try-on as a consumer feature, or
individual recommendation decisions — those belong to Aglaea. Freya publishes
products, textiles, sizing, retail inventory, brand campaigns, and provenance
records; Aglaea consumes them for consumer recommendation and shopping
experiences. Stores, factories, and real-estate facilities belong to Cybele;
factory-automation machinery belongs to Brigid; advanced technology-product
manufacturing belongs to Saraswati. The @freya/connectors library is the sole
integration boundary to Asase, Brigid, Cybele, Saraswati, and Maat — no
capability library imports from those domains directly.
Verification Expectations#
Changes run package tests for affected libraries and apps (Vitest — every
library has a vitest.config.ts and a *.spec.ts suite). Commerce, payment,
inventory, manufacturing, and customer-data changes additionally require
contract and persistence regression coverage. Tests must assert specific
computed values against known-correct answers; asserting only shape or
truthiness is not sufficient for the domain's financial, quality, and
formulation logic.