Katkat

Design a scalable expense rules engine

RipplingSoftware Engineer · Technical Screen

Last updated

This question evaluates system-design and data-modeling competency for building a scalable, multi-tenant rules engine (category: System Design) that supports per-entity and aggregate (trip-level) evaluations, backward-compatible APIs, explainability/auditability, parsing/validation of string-typed inputs, and operational concerns like determinism, idempotency, and resilience. It is commonly asked to assess trade-off reasoning around extensibility, evaluation semantics (priority, combinators, short-circuiting), aggregation and caching strategies, and API/data-model stability, with a level of abstraction that is practical application focused while requiring conceptual architectural trade-offs and concrete design details.

Design a rules engine to evaluate corporate credit-card expenses and flag items for manager review.

Initial requirements:

  • Enforce base rules: (
  1. no restaurant expense over $75, (
  2. no airfare expenses, (
  3. no entertainment expenses, (
  4. no expense over $250.
  • Inputs: expenses provided as a list of dictionary objects with string keys and values.
  • Define types for rules (your choice) and propose the function evaluateRules(rules: list<Rule>, expenses: list<Expense>) -> ReturnType, where the return will be used by an expenses API serving many companies.

Design goals:

  • Support 100+ rules selected per manager/team; allow adding new rules and rule creation via an API without breaking clients.
  • Specify evaluation semantics: priority/ordering, combinators (AND/OR/NOT), short-circuiting vs exhaustive evaluation, and conflict resolution.
  • Provide explainability/audit: per-violation reason, rule metadata, timestamps, and who/what policy triggered the violation.
  • Address multi-tenant isolation, authorization, observability, idempotency, deterministic ordering, and resilience to partial failures.
  • Define core data models (Expense, Trip, Rule, Policy, RuleResult, EvaluationSummary) and how string-typed inputs are parsed/validated (amounts, categories, vendor types).

Extension (aggregate rules):

  • Add group-by rules such as: (a) a trip’s total expenses must not exceed $2000, and (b) total meal expenses per trip must not exceed $200. In the provided sample, trip "002" violates both.
  • Extend the engine to evaluate both per-entity (expense) and aggregate (trip) rules in one pass; describe aggregation strategy, caching, and incremental updates.
  • Propose a backward-compatible ReturnType that surfaces both expense-level and trip-level violations: entity type (expense/trip), identifiers (expense_id/trip_id), violated rule codes, severity, human-readable messages, machine-readable fields, and pagination.

Product questions to clarify:

  • How are policies scoped (company/team/user) and how do overrides/precedence work?
  • Currency/FX handling, locales, tax/tip treatment for meal caps, per-diem vs per-transaction limits.
  • Category taxonomy (expense_type, vendor_type), who classifies, and how to handle unknown/mislabeled categories.
  • Time windows (per trip/day/month), receipt requirements, exception workflows and approvals, SLAs/notifications.
  • Versioning and rollout (A/B, canary), API rate limits, and return-type compatibility strategy over time.