diff --git a/backend/innercontext/api/products.py b/backend/innercontext/api/products.py index 801d21f..fda0a79 100644 --- a/backend/innercontext/api/products.py +++ b/backend/innercontext/api/products.py @@ -21,11 +21,8 @@ from innercontext.models.product import ( from innercontext.models.enums import ( AbsorptionSpeed, DayTime, - EvidenceLevel, PriceTier, - RoutineRole, TextureType, - UsageFrequency, SkinType, ) @@ -46,7 +43,6 @@ class ProductCreate(SQLModel): barcode: Optional[str] = None category: ProductCategory - routine_role: RoutineRole recommended_time: DayTime texture: Optional[TextureType] = None @@ -61,13 +57,10 @@ class ProductCreate(SQLModel): actives: Optional[list[ActiveIngredient]] = None recommended_for: list[SkinType] = [] - recommended_frequency: Optional[UsageFrequency] = None targets: list[SkinConcern] = [] contraindications: list[str] = [] usage_notes: Optional[str] = None - evidence_level: Optional[EvidenceLevel] = None - claims: list[str] = [] fragrance_free: Optional[bool] = None essential_oils_free: Optional[bool] = None @@ -104,7 +97,6 @@ class ProductUpdate(SQLModel): barcode: Optional[str] = None category: Optional[ProductCategory] = None - routine_role: Optional[RoutineRole] = None recommended_time: Optional[DayTime] = None texture: Optional[TextureType] = None @@ -119,13 +111,10 @@ class ProductUpdate(SQLModel): actives: Optional[list[ActiveIngredient]] = None recommended_for: Optional[list[SkinType]] = None - recommended_frequency: Optional[UsageFrequency] = None targets: Optional[list[SkinConcern]] = None contraindications: Optional[list[str]] = None usage_notes: Optional[str] = None - evidence_level: Optional[EvidenceLevel] = None - claims: Optional[list[str]] = None fragrance_free: Optional[bool] = None essential_oils_free: Optional[bool] = None diff --git a/backend/innercontext/models/product.py b/backend/innercontext/models/product.py index 6905bfa..961f9a8 100644 --- a/backend/innercontext/models/product.py +++ b/backend/innercontext/models/product.py @@ -11,17 +11,14 @@ from .domain import Domain from .enums import ( AbsorptionSpeed, DayTime, - EvidenceLevel, IngredientFunction, InteractionScope, PriceTier, ProductCategory, - RoutineRole, SkinConcern, SkinType, StrengthLevel, TextureType, - UsageFrequency, ) @@ -60,8 +57,6 @@ class ActiveIngredient(SQLModel): strength_level: StrengthLevel | None = None irritation_potential: StrengthLevel | None = None - cumulative_with: list[IngredientFunction] | None = None - class ProductInteraction(SQLModel): target: str @@ -106,7 +101,6 @@ class Product(SQLModel, table=True): barcode: str | None = Field(default=None, max_length=64) category: ProductCategory - routine_role: RoutineRole recommended_time: DayTime texture: TextureType | None = None @@ -127,7 +121,6 @@ class Product(SQLModel, table=True): recommended_for: list[SkinType] = Field( default_factory=list, sa_column=Column(JSON, nullable=False) ) - recommended_frequency: UsageFrequency | None = None targets: list[SkinConcern] = Field( default_factory=list, sa_column=Column(JSON, nullable=False) @@ -136,10 +129,6 @@ class Product(SQLModel, table=True): default_factory=list, sa_column=Column(JSON, nullable=False) ) usage_notes: str | None = None - evidence_level: EvidenceLevel | None = Field(default=None, index=True) - claims: list[str] = Field( - default_factory=list, sa_column=Column(JSON, nullable=False) - ) fragrance_free: bool | None = None essential_oils_free: bool | None = None @@ -221,12 +210,11 @@ class Product(SQLModel, table=True): "name": self.name, "brand": self.brand, "category": _ev(self.category), - "routine_role": _ev(self.routine_role), "recommended_time": _ev(self.recommended_time), "leave_on": self.leave_on, } - for field in ("line_name", "sku", "url", "barcode"): + for field in ("line_name", "url"): val = getattr(self, field) if val is not None: ctx[field] = val @@ -241,11 +229,6 @@ class Product(SQLModel, table=True): ctx["size_ml"] = self.size_ml if self.pao_months is not None: ctx["pao_months"] = self.pao_months - if self.recommended_frequency is not None: - ctx["recommended_frequency"] = _ev(self.recommended_frequency) - if self.evidence_level is not None: - ctx["evidence_level"] = _ev(self.evidence_level) - if self.inci: ctx["inci"] = self.inci if self.recommended_for: @@ -254,8 +237,6 @@ class Product(SQLModel, table=True): ctx["targets"] = [_ev(s) for s in self.targets] if self.contraindications: ctx["contraindications"] = self.contraindications - if self.claims: - ctx["claims"] = self.claims if self.actives: actives_ctx = [] @@ -270,8 +251,6 @@ class Product(SQLModel, table=True): a_dict["functions"] = [_ev(f) for f in a.functions] if a.strength_level is not None: a_dict["strength_level"] = a.strength_level.name.lower() - if a.cumulative_with: - a_dict["cumulative_with"] = [_ev(f) for f in a.cumulative_with] actives_ctx.append(a_dict) ctx["actives"] = actives_ctx @@ -288,9 +267,9 @@ class Product(SQLModel, table=True): ep = self.product_effect_profile if ep is not None: if isinstance(ep, dict): - nonzero = {k: v for k, v in ep.items() if v} + nonzero = {k: v for k, v in ep.items() if v >= 2} else: - nonzero = {k: v for k, v in ep.model_dump().items() if v} + nonzero = {k: v for k, v in ep.model_dump().items() if v >= 2} if nonzero: ctx["effect_profile"] = nonzero diff --git a/backend/tests/conftest.py b/backend/tests/conftest.py index c2a5721..7085b78 100644 --- a/backend/tests/conftest.py +++ b/backend/tests/conftest.py @@ -53,7 +53,6 @@ def product_data(): "name": "CeraVe Moisturising Cream", "brand": "CeraVe", "category": "moisturizer", - "routine_role": "seal", "recommended_time": "both", "leave_on": True, } diff --git a/backend/tests/test_product_model.py b/backend/tests/test_product_model.py index a75e102..36660f1 100644 --- a/backend/tests/test_product_model.py +++ b/backend/tests/test_product_model.py @@ -9,7 +9,6 @@ from innercontext.models.enums import ( IngredientFunction, InteractionScope, ProductCategory, - RoutineRole, ) from innercontext.models.product import ( ActiveIngredient, @@ -25,7 +24,6 @@ def _make(**kwargs): name="Test", brand="B", category=ProductCategory.MOISTURIZER, - routine_role=RoutineRole.SEAL, recommended_time=DayTime.BOTH, leave_on=True, ) @@ -41,7 +39,7 @@ def _make(**kwargs): def test_always_present_keys(): p = _make() ctx = p.to_llm_context() - for key in ("id", "name", "brand", "category", "routine_role", "recommended_time", "leave_on"): + for key in ("id", "name", "brand", "category", "recommended_time", "leave_on"): assert key in ctx, f"Expected '{key}' in to_llm_context() output" @@ -53,17 +51,17 @@ def test_always_present_keys(): def test_optional_string_fields_absent_when_none(): p = _make() ctx = p.to_llm_context() - for key in ("line_name", "sku", "url", "barcode"): + for key in ("line_name", "url"): assert key not in ctx, f"'{key}' should not appear when None" def test_optional_string_fields_present_when_set(): - p = _make(line_name="Hydrating", sku="CV-001", url="https://example.com", barcode="123456") + p = _make(line_name="Hydrating", url="https://example.com") ctx = p.to_llm_context() assert ctx["line_name"] == "Hydrating" - assert ctx["sku"] == "CV-001" assert ctx["url"] == "https://example.com" - assert ctx["barcode"] == "123456" + assert "sku" not in ctx + assert "barcode" not in ctx # --------------------------------------------------------------------------- diff --git a/backend/tests/test_products.py b/backend/tests/test_products.py index 098df1b..f550a69 100644 --- a/backend/tests/test_products.py +++ b/backend/tests/test_products.py @@ -52,7 +52,6 @@ def test_list_filter_category(client, client_and_data=None): # Create a moisturizer and a serum base = { "brand": "B", - "routine_role": "seal", "recommended_time": "both", "leave_on": True, } @@ -72,7 +71,6 @@ def test_list_filter_category(client, client_and_data=None): def test_list_filter_brand(client): base = { - "routine_role": "seal", "recommended_time": "both", "leave_on": True, "category": "serum", @@ -90,7 +88,6 @@ def test_list_filter_brand(client): def test_list_filter_is_medication(client): base = { "brand": "B", - "routine_role": "seal", "recommended_time": "both", "leave_on": True, "category": "serum", @@ -113,7 +110,6 @@ def test_list_filter_is_medication(client): def test_list_filter_targets(client): base = { "brand": "B", - "routine_role": "seal", "recommended_time": "both", "leave_on": True, "category": "serum", diff --git a/frontend/src/lib/types.ts b/frontend/src/lib/types.ts index d225660..affc1ea 100644 --- a/frontend/src/lib/types.ts +++ b/frontend/src/lib/types.ts @@ -3,7 +3,6 @@ export type AbsorptionSpeed = 'very_fast' | 'fast' | 'moderate' | 'slow' | 'very_slow'; export type BarrierState = 'intact' | 'mildly_compromised' | 'compromised'; export type DayTime = 'am' | 'pm' | 'both'; -export type EvidenceLevel = 'low' | 'mixed' | 'moderate' | 'high'; export type GroomingAction = 'shaving_razor' | 'shaving_oneblade' | 'dermarolling'; export type IngredientFunction = | 'humectant' @@ -44,14 +43,6 @@ export type ProductCategory = | 'spot_treatment' | 'oil'; export type ResultFlag = 'N' | 'ABN' | 'POS' | 'NEG' | 'L' | 'H'; -export type RoutineRole = - | 'cleanse' - | 'prepare' - | 'treatment_active' - | 'treatment_support' - | 'seal' - | 'protect' - | 'hair_treatment'; export type SkinConcern = | 'acne' | 'rosacea' @@ -68,15 +59,6 @@ export type SkinTrend = 'improving' | 'stable' | 'worsening' | 'fluctuating'; export type SkinType = 'dry' | 'oily' | 'combination' | 'sensitive' | 'normal' | 'acne_prone'; export type StrengthLevel = 1 | 2 | 3; export type TextureType = 'watery' | 'gel' | 'emulsion' | 'cream' | 'oil' | 'balm' | 'foam' | 'fluid'; -export type UsageFrequency = - | 'daily' - | 'twice_daily' - | 'every_other_day' - | 'twice_weekly' - | 'three_times_weekly' - | 'weekly' - | 'as_needed'; - // ─── Product types ─────────────────────────────────────────────────────────── export interface ActiveIngredient { @@ -85,7 +67,6 @@ export interface ActiveIngredient { functions: IngredientFunction[]; strength_level?: StrengthLevel; irritation_potential?: StrengthLevel; - cumulative_with?: IngredientFunction[]; } export interface ProductEffectProfile { @@ -140,7 +121,6 @@ export interface Product { url?: string; barcode?: string; category: ProductCategory; - routine_role: RoutineRole; recommended_time: DayTime; texture?: TextureType; absorption_speed?: AbsorptionSpeed; @@ -151,12 +131,9 @@ export interface Product { inci: string[]; actives?: ActiveIngredient[]; recommended_for: SkinType[]; - recommended_frequency?: UsageFrequency; targets: SkinConcern[]; contraindications: string[]; usage_notes?: string; - evidence_level?: EvidenceLevel; - claims: string[]; fragrance_free?: boolean; essential_oils_free?: boolean; alcohol_denat_free?: boolean; diff --git a/frontend/src/routes/products/[id]/+page.svelte b/frontend/src/routes/products/[id]/+page.svelte index 099510a..9954d97 100644 --- a/frontend/src/routes/products/[id]/+page.svelte +++ b/frontend/src/routes/products/[id]/+page.svelte @@ -37,7 +37,6 @@