# CreateNotificationTemplate

## Permission Scope

template

## Overview

createNotificationTemplate inserts a NotificationTemplate row keyed by the triple `(eventType, channelId, locale)`. The template carries a `subject`, a plain-text `body`, an optional `htmlBody` (for rich channels such as EMAIL), and a declared `variableSchema` describing the placeholders the template expects at render time. The triple is unique — a second row with the same `(eventType, channelId, locale)` is rejected. At save time the command validates that every `{{variable}}` reference appearing in `subject` / `body` / `htmlBody` is declared in the `variableSchema`, so authoring errors are caught before runtime rather than producing broken renders.

## Business Rules

- `eventType` is required and must be present in the dispatcher's Event Catalog
- `channelId` is required and must reference an existing NotificationChannel row
- `locale` is required (BCP-47 string)
- `subject` and `body` are required and must be non-blank after trimming
- `htmlBody` is optional; when present, must be non-blank
- `variableSchema` is required and declares each variable with a name and type
- The triple `(eventType, channelId, locale)` must be unique
- Every `{{variable}}` reference appearing in `subject`, `body`, or `htmlBody` must be declared in `variableSchema`

## Process Flow

```mermaid
flowchart TD
    A[Receive create template request] --> B{eventType, channelId, locale, subject, body, variableSchema all present and non-blank?}
    B -->|No| C[Return MISSING_REQUIRED_FIELD]
    B -->|Yes| D{eventType present in Event Catalog?}
    D -->|No| E[Return EVENT_TYPE_NOT_FOUND]
    D -->|Yes| F{NotificationChannel exists for channelId?}
    F -->|No| G[Return CHANNEL_NOT_FOUND]
    F -->|Yes| H{Existing NotificationTemplate for (eventType, channelId, locale)?}
    H -->|Yes| I[Return DUPLICATE_TEMPLATE_KEY]
    H -->|No| J[Scan subject / body / htmlBody for placeholder references]
    J --> K{Every placeholder declared in variableSchema?}
    K -->|No| L[Return UNDECLARED_VARIABLE_REFERENCE]
    K -->|Yes| M[Insert NotificationTemplate row]
    M --> N[Return template id and triple]
```

## External Dependencies

- None (operates on module-owned NotificationTemplate, NotificationChannel registry, and Event Catalog)

## Error Scenarios

- **DUPLICATE_TEMPLATE_KEY**: A NotificationTemplate row already exists for the supplied `(eventType, channelId, locale)` triple
- **CHANNEL_NOT_FOUND**: No NotificationChannel row matches the supplied channelId
- **EVENT_TYPE_NOT_FOUND**: `eventType` is absent from the dispatcher's Event Catalog
- **MISSING_REQUIRED_FIELD**: One or more required input fields are missing or blank
- **UNDECLARED_VARIABLE_REFERENCE**: subject / body / htmlBody contains a {{variable}} reference that is not declared in variableSchema

## Test Cases

- creates a NotificationTemplate row for a new (eventType, channelId, locale) triple
- creates an EMAIL template that includes htmlBody alongside subject and body
- creates an IN_APP template without htmlBody
- returns DUPLICATE_TEMPLATE_KEY when a row for the same triple already exists
- returns CHANNEL_NOT_FOUND when channelId does not match any NotificationChannel row
- returns EVENT_TYPE_NOT_FOUND when eventType is not in the Event Catalog
- returns MISSING_REQUIRED_FIELD when subject is blank
- returns MISSING_REQUIRED_FIELD when variableSchema is omitted
- returns UNDECLARED_VARIABLE_REFERENCE when body references a variable not in variableSchema
- subsequent renders for the triple resolve to the newly created row
