# Recommendation Engine Contracts (Rule-Based) > **No AI. No implementation.** Contracts for a future rule evaluator. > ADR: [ADR-023](../architecture/adr/ADR-023.md) > Contract version: `recommendation.v1` --- ## 1. Purpose Produce **recommendations** for bundles, services, modules, features, and pricing from structured business inputs. Outputs never activate entitlements. --- ## 2. Input — RecommendationRequest | Field | Type | Meaning | | --- | --- | --- | | `business_type_code` | string | From Business Type Catalog | | `company_size` | enum | `solo` \| `small` \| `medium` \| `large` \| `enterprise` | | `employees` | int? | Headcount hint | | `branches` | int? | Location count | | `needs[]` | string[] | Free-form need tags (open registry) | | `online_sales` | bool | | | `delivery` | bool | | | `appointments` | bool | | | `crm` | bool | | | `loyalty` | bool | | | `website` | bool | | | `locale` | string? | | | `ext` | object | Additive | ### Need tag examples (open) `menu`, `pos`, `fleet`, `sms`, `accounting`, `membership`, `forms`, `b2b_pipeline` --- ## 3. Output — RecommendationResult | Field | Type | Meaning | | --- | --- | --- | | `recommended_bundles[]` | RankedRef | `{ code, score, reason }` | | `recommended_services[]` | RankedRef | `service_identifier` | | `recommended_modules[]` | RankedRef | `module_key` | | `recommended_features[]` | RankedRef | `feature_key` | | `recommended_pricing[]` | RankedRef | `pricing_item_code` | | `rule_trace[]` | string[] | Which rules fired (debug) | | `version` | string | `recommendation.v1` | --- ## 4. Rule — RecommendationRule | Field | Type | Meaning | | --- | --- | --- | | `rule_id` | string | | | `priority` | int | Higher evaluated first / stronger weight | | `active` | bool | | | `match` | object | Predicates over RecommendationRequest | | `emit` | object | What to add to result with `score` + `reason` | | `stop` | bool | If true, halt further rules after match | ### Match predicates (documented operators) | Operator | Example | | --- | --- | | `eq` | `business_type_code eq restaurant` | | `gte` | `branches gte 2` | | `in` | `company_size in [medium, large, enterprise]` | | `flag_true` | `delivery == true` | | `needs_contains` | `needs contains fleet` | ### Example rules (illustrative) | rule_id | Match | Emit | | --- | --- | --- | | `r.restaurant.base` | type=restaurant | bundle `bundle.restaurant.starter` score 100 | | `r.delivery.need` | delivery=true | service `delivery` score 80 | | `r.crm.need` | crm=true OR type=corporate_company | service `crm` score 80 | | `r.website.need` | website=true | service `experience` score 70 | | `r.loyalty.need` | loyalty=true | service `loyalty` score 70 | | `r.multi.branch` | branches≥3 | prefer `*.growth` bundle variants score +20 | | `r.enterprise.size` | company_size=enterprise | pricing `price.enterprise.custom` score 90 | --- ## 5. Invariants 1. Rules MUST NOT call Payment, Accounting, or vertical write APIs. 2. Scores are relative; UI may sort but MUST present as recommendations. 3. No ML / LLM required or permitted by this contract version.