Rules Engine
The RulesEngine is a pure business logic component (IDesign Engine layer) that evaluates company policies deterministically. It never makes I/O calls -- it receives data and returns pass/fail decisions with reasons.
Design Principles
- Deterministic -- same input always produces the same result, no LLM involved
- Configurable -- rules are YAML, not code; customers can customize via dashboard
- Auditable -- every evaluation is logged with rule name, input, and result
- Composable -- rules can reference other rules and combine with AND/OR logic
Rule Evaluation Flow
Input Data ──→ RulesEngine.evaluate(rule_type, data)
│
├── Load rules for company + rule_type
├── Evaluate each rule condition
├── Return: PASS | WARN | FAIL + reasons[]
└── Log evaluation to audit trail
Rule Types
1. Expense Policy (expense_policy)
Controls what expenses employees can submit and what requires approval.
rule_type: expense_policy
config:
travel:
max_daily_rate: 800 # NOK per diem
receipt_required_above: 500 # NOK
approval_required_above: 5000
allowed_categories:
- taxi
- flight
- train
- hotel
- meals
- parking
forbidden_categories:
- alcohol
- entertainment_personal
max_single_expense: 20000
max_monthly_per_employee: 50000
office:
receipt_required_above: 200
approval_required_above: 2000
max_single_expense: 10000
representation:
max_per_person: 550 # Tax-deductible limit (2026)
max_attendees: 20
requires_attendee_list: true
requires_business_purpose: true
Evaluation example:
Input: {category: "taxi", amount: 1200, has_receipt: false, employee_id: 12}
Rule: receipt_required_above: 500
Result: FAIL — "Kvittering påkrevd for beløp over 500 kr (beløp: 1 200 kr)"
2. Approval Thresholds (approval_threshold)
Defines who can approve what, based on amount and category.
rule_type: approval_threshold
config:
levels:
- max_amount: 5000
approver: auto # No human approval needed
- max_amount: 25000
approver: department_manager
- max_amount: 100000
approver: cfo
- max_amount: null # Unlimited
approver: ceo
overrides:
- category: representation
always_requires: department_manager
- category: it_equipment
above: 10000
requires: it_manager
3. Account Mapping (account_mapping)
Rules for automatically selecting the correct ledger account based on expense category, supplier, or description.
rule_type: account_mapping
config:
by_category:
taxi: 7140 # Reise og diett
flight: 7140
hotel: 7140
meals_business: 7350 # Representasjon
meals_travel: 7140
office_supplies: 6540
software: 6440 # Programvare
phone: 6900
internet: 6900
postage: 6800
cleaning: 6360
by_supplier_org_number:
"923609016": 6900 # Telenor → Telefon
"985615616": 6440 # Microsoft → Programvare
"979191138": 6900 # Telia → Telefon
by_description_pattern:
- pattern: "(?i)fly|flight|sas|norwegian|wideroe"
account: 7140
- pattern: "(?i)hotell|hotel|scandic|thon|radisson"
account: 7140
- pattern: "(?i)parkering|parking|apcoa|europark"
account: 7160
- pattern: "(?i)drivstoff|bensin|diesel|circle.k|esso|shell"
account: 7020
default_account: 7700 # Annen kostnad
4. Payment Deadline (payment_deadline)
Controls when to alert about upcoming and overdue payments.
rule_type: payment_deadline
config:
alert_days_before_due: 3
overdue_alert_intervals: [1, 3, 7, 14, 30] # days after due date
escalation:
- days_overdue: 7
notify: accountant
- days_overdue: 14
notify: [accountant, cfo]
- days_overdue: 30
notify: [accountant, cfo, ceo]
action: suggest_reminder
customer_invoices:
reminder_after_days: 14
second_reminder_after_days: 28
collection_after_days: 42
reminder_fee: 70 # NOK (inkassovarsel)
interest_rate: 0.0833 # Forsinkelsesrente per month
5. Payroll Validation (payroll_validation)
Flags anomalies in payroll before processing.
rule_type: payroll_validation
config:
deviation_threshold_percent: 20 # Flag if salary deviates >20% from 6-month average
max_overtime_hours: 40 # Per month
min_gross_salary: 0 # Allow zero (unpaid leave)
max_gross_salary: 200000 # NOK per month
require_timesheet: true # Must have timesheet entries for hourly employees
statutory:
employer_tax_rate: 0.141 # Arbeidsgiveravgift zone 1
holiday_pay_rate: 0.12 # Feriepenger (12% standard, 14.3% for 60+)
holiday_pay_rate_senior: 0.143
senior_age: 60
6. VAT Validation (vat_validation)
Ensures correct VAT treatment on all transactions.
rule_type: vat_validation
config:
rates:
standard: 0.25
food: 0.15
transport: 0.12
exempt: 0.00
outside_scope: null
rules:
- description: "Domestic goods and services default to 25%"
condition: "country == 'NO' && !is_exempt"
expected_rate: 0.25
- description: "Food and beverages at 15%"
condition: "account >= 4000 && account <= 4099"
expected_rate: 0.15
- description: "Passenger transport at 12%"
condition: "category == 'transport' && is_passenger"
expected_rate: 0.12
- description: "Reverse charge on foreign services"
condition: "country != 'NO' && is_service"
expected_rate: 0.25
note: "Both ingoing and outgoing VAT must be recorded"
flag_missing_vat: true
flag_zero_vat_domestic: true
7. Month-End Checklist (month_end_checklist)
Defines what must be completed before a month can be closed.
rule_type: month_end_checklist
config:
items:
- id: depreciation
description: "Avskrivninger bokført"
check: "voucher exists with description matching 'avskriv' for period"
required: true
- id: salary_reconciliation
description: "Lønn avstemt mot bank"
check: "salary total matches bank outflow"
required: true
- id: supplier_accruals
description: "Leverandørfakturaer periodisert"
check: "no supplier invoices dated next month with voucher in current month"
required: true
- id: prepaid_expenses
description: "Forutbetalte kostnader fordelt"
check: "account 1700-1799 reviewed"
required: false
reminder: true
- id: trial_balance
description: "Saldobalanse generert og gjennomgått"
check: "trial balance generated"
required: true
- id: vat_return
description: "MVA-oppgave klargjort"
check: "VAT postings balanced"
required: true
frequency: bimonthly # Only in odd-numbered months
8. Compliance Rules (compliance)
Norwegian accounting law (bokforingsloven) requirements.
rule_type: compliance
config:
bokforingsloven:
- rule: "Every transaction must have a voucher"
check: "no postings without voucher_id"
severity: critical
- rule: "Vouchers must have date, description, and amount"
check: "all vouchers have non-null date, description, postings"
severity: critical
- rule: "No backdating beyond 30 days"
check: "voucher_date >= today - 30"
severity: warning
- rule: "Attachments required for external vouchers"
check: "supplier_invoices have attachment_count > 0"
severity: warning
- rule: "Sequential voucher numbering"
check: "no gaps in voucher number sequence per year"
severity: warning
retention:
primary_documentation: 3650 # 10 years in days
secondary_documentation: 1825 # 5 years in days
audit_trail: 3650
Combining Rules
Rules can be combined using logical operators:
combined_rule:
all_of: # AND
- rule: expense_policy.travel
- rule: approval_threshold
- rule: vat_validation
any_of: # OR (pass if any passes)
- rule: account_mapping.by_supplier_org_number
- rule: account_mapping.by_description_pattern
- rule: account_mapping.by_category
Custom Rules
Companies can add custom rules via the dashboard or API:
rule_type: custom
config:
name: "Friday lunch limit"
description: "Lunch expenses on Fridays capped at 200 kr per person"
condition: "category == 'meals' && day_of_week == 5"
max_amount_per_person: 200
action: warn