# Calendar Rules Engine {#calendar-rules-engine}



## Overview {#overview}


The calendar rules engine enables dynamic, date-based survey logic. It auto-prefills calendar grid columns based on answers to previous questions, supporting complex scheduling and conditional display.


## Architecture {#architecture}


The rules engine spans two services:

- **survey-service**: Stores `calendar_rules` in the survey JSONB schema
- **form-service**: Evaluates rules at render time via the calendar rules engine

The frontend also has a client-side implementation at `frontend/app/src/lib/calendar-rules-engine.ts`.


## Rule Structure {#rule-structure}


```python
class CalendarRule(BaseModel):
    target_column: str                     # Column to auto-fill
    conditions: List[RuleCondition]        # When to apply
    logic: Literal["AND", "OR"] = "AND"    # Condition combination
    months_scope: MonthScope               # Which months to affect
    value_source: ValueSource              # Where values come from
```


## Conditions {#conditions}


Rules apply only when all (AND) or any (OR) conditions are met:

```python
conditions = [
    {"question_id": "pregnancy", "operator": "eq", "value": "yes"},
    {"question_id": "age", "operator": "gte", "value": 18},
]
```


## Month Scopes {#month-scopes}


| Scope | Description |
|-------|-------------|
| `current` | Only current month |
| `last_n` | Last N months (static number) |
| `all_past` | All past months |
| `from_answer` | Use answer value for number of months |
| `custom` | Static from/to month range |
| `custom_from_answer` | Dynamic from/to using two questions |


## Value Sources {#value-sources}


| Source | Description |
|--------|-------------|
| `fixed` | Constant value |
| `lookup` | Map trigger question answers to target values |
| `xpath` | Expression evaluation |


## Example {#example}


```json
{
  "calendar_rules": [
    {
      "target_column": "monthly_visit",
      "conditions": [
        {"question_id": "needs_followup", "operator": "eq", "value": "yes"}
      ],
      "logic": "AND",
      "months_scope": {"type": "last_n", "value": 6},
      "value_source": {"type": "fixed", "value": "Scheduled"}
    }
  ]
}
```


## Engine Behavior {#engine-behavior}


- **Auto-fill**: Target column cells are pre-filled when conditions are met
- **Toggle**: Cells are cleared when conditions are no longer met
- **Trigger on dependency**: Recalculates when `months_scope.from_question` or `months_scope.to_question` answers change


## Frontend Integration {#frontend-integration}


```typescript
// Client-side rules engine
import { applyCalendarRules } from "@/lib/calendar-rules-engine";

const updatedForm = applyCalendarRules(surveySchema, currentAnswers);
```
