HEX
Server: Apache/2.4.46 (Win64) OpenSSL/1.1.1j PHP/8.4.25
System: Windows NT DESKTOP-4TAV2RJ 10.0 build 19045 (Windows 10) AMD64
User: fred (0)
PHP: 8.4.25
Disabled: NONE
Upload Files
File: C:/Users/fred/.codex/.tmp/plugins/plugins/base44/skills/base44-cli/references/automations.md
# Function Automations

Automations are triggers attached to backend functions. They cause a function to run automatically on a schedule (CRON, simple interval, or one-time) or when entity data changes (create, update, delete). Automations are defined in the `automations` array inside each function's `function.jsonc` and are deployed together with the function via `npx base44 functions deploy`.

## Overview

- **Where**: `base44/functions/<function-name>/function.jsonc` — optional `automations` array
- **Deploy**: Automations are deployed with the function; no separate command
- **Types**: Scheduled (one-time, CRON, simple interval) and entity hooks

## Common Fields (All Automation Types)

Every automation shares these base fields:

| Property | Type | Required | Description |
|----------|------|----------|-------------|
| `name` | string | Yes | Display name for the automation (min 1 char) |
| `description` | string \| null | No | Optional description |
| `function_args` | object \| null | No | Key-value args passed to the function when it runs |
| `is_active` | boolean | No | Whether the automation is active (default: `true`) |

## Automation Types

### 1. Scheduled One-Time

Runs the function once at a specific date/time.

| Property | Type | Required | Description |
|----------|------|----------|-------------|
| `type` | `"scheduled"` | Yes | Must be `"scheduled"` |
| `schedule_mode` | `"one-time"` | Yes | One-time execution |
| `one_time_date` | string | Yes | ISO date/time when the function should run (e.g. `"2024-01-15T10:00:00"`) |

**Example:**

```jsonc
{
  "name": "my-function",
  "entry": "index.ts",
  "automations": [
    {
      "name": "Launch reminder",
      "type": "scheduled",
      "schedule_mode": "one-time",
      "one_time_date": "2026-03-01T09:00:00.000Z",
      "description": "One-time reminder on launch day"
    }
  ]
}
```

### 2. Scheduled CRON (Recurring)

Runs the function on a cron schedule. **Minimum interval is 5 minutes.**

| Property | Type | Required | Description |
|----------|------|----------|-------------|
| `type` | `"scheduled"` | Yes | Must be `"scheduled"` |
| `schedule_mode` | `"recurring"` | Yes | Recurring execution |
| `schedule_type` | `"cron"` | Yes | Use cron expression |
| `cron_expression` | string | Yes | Standard cron: `minute hour day-of-month month day-of-week` |
| `ends_type` | `"never"` \| `"on"` \| `"after"` | No | When the schedule stops (default: `"never"`) |
| `ends_on_date` | string \| null | No | When `ends_type` is `"on"`, ISO date to stop |
| `ends_after_count` | number \| null | No | When `ends_type` is `"after"`, number of runs then stop |

**End conditions** (apply to both CRON and simple recurring):
- `ends_type="never"` — Run indefinitely (default)
- `ends_type="on"` — Run until a date: set `ends_on_date` (e.g. `"2024-12-31T23:59:59"`)
- `ends_type="after"` — Run N times: set `ends_after_count` (e.g. `10`)

**Cron format:** `minute hour day-of-month month day-of-week`

**Examples:**
- `"*/5 * * * *"` — every 5 minutes (minimum interval)
- `"0 9 * * *"` — 9am daily
- `"0 9 * * 1-5"` — 9am every weekday (Mon–Fri)

**Example:**

```jsonc
{
  "name": "daily-report",
  "entry": "index.ts",
  "automations": [
    {
      "name": "Daily Report",
      "type": "scheduled",
      "schedule_mode": "recurring",
      "schedule_type": "cron",
      "cron_expression": "0 9 * * *",
      "description": "Run every day at 9:00 UTC",
      "is_active": true
    }
  ]
}
```

### 3. Scheduled Simple (Recurring Interval)

Runs the function on a simple repeat (every N minutes/hours/days/weeks/months). **Minimum interval for minutes is 5** (e.g. every 5 minutes).

| Property | Type | Required | Description |
|----------|------|----------|-------------|
| `type` | `"scheduled"` | Yes | Must be `"scheduled"` |
| `schedule_mode` | `"recurring"` | Yes | Recurring execution |
| `schedule_type` | `"simple"` | Yes | Use simple interval |
| `repeat_unit` | `"minutes"` \| `"hours"` \| `"days"` \| `"weeks"` \| `"months"` | Yes | Unit of repetition |
| `repeat_interval` | number | No | Positive integer; interval within the unit (default 1). For minutes, minimum is 5. |
| `start_time` | string \| null | No | Time of day (e.g. `"09:00"`, `"00:00"`) |
| `repeat_on_days` | number[] \| null | No | For weeks: 0–6 (0 = Sunday, 6 = Saturday) |
| `repeat_on_day_of_month` | number \| null | No | For months: 1–31 |
| `ends_type` | `"never"` \| `"on"` \| `"after"` | No | When the schedule stops (default: `"never"`) |
| `ends_on_date` | string \| null | No | When `ends_type` is `"on"`, ISO date to stop |
| `ends_after_count` | number \| null | No | When `ends_type` is `"after"`, number of runs then stop |

**End conditions:** Same as for CRON — `ends_type` / `ends_on_date` / `ends_after_count` (see Scheduled CRON above).

**Simple schedule examples:**
- Every 5 minutes: `repeat_interval=5`, `repeat_unit="minutes"` (minimum)
- Hourly: `repeat_interval=1`, `repeat_unit="hours"`
- Daily at specific time: `repeat_interval=1`, `repeat_unit="days"`, `start_time="09:00"`
- Weekly on specific days: `repeat_unit="weeks"`, `repeat_on_days=[1, 5]`, `start_time="10:00"` (e.g. Mon and Fri)
- Monthly on specific day: `repeat_unit="months"`, `repeat_on_day_of_month=15`, `start_time="00:00"`

**Example:**

```jsonc
{
  "name": "weekly-cleanup",
  "entry": "index.ts",
  "automations": [
    {
      "name": "Weekly Cleanup",
      "type": "scheduled",
      "schedule_mode": "recurring",
      "schedule_type": "simple",
      "repeat_unit": "weeks",
      "repeat_interval": 1,
      "repeat_on_days": [1],
      "start_time": "02:00",
      "description": "Every Monday at 2:00"
    }
  ]
}
```

### 4. Entity Hook

Runs the function when entity records are created, updated, or deleted.

**Required:** `entity_name`, `event_types` (array of `"create"`, `"update"`, `"delete"` — at least one).

| Property | Type | Required | Description |
|----------|------|----------|-------------|
| `type` | `"entity"` | Yes | Must be `"entity"` |
| `entity_name` | string | Yes | Entity name (matches entity schema name, e.g. `Order`, `Task`) |
| `event_types` | `("create" \| "update" \| "delete")[]` | Yes | At least one; which events trigger the function |

**Example use cases:**
- Send email on new order: `entity_name="Order"`, `event_types=["create"]`
- Track status changes: `entity_name="Order"`, `event_types=["update"]`
- Cleanup on delete: `entity_name="User"`, `event_types=["delete"]`
- Multiple events: `entity_name="Order"`, `event_types=["create", "update"]`

**Example config:**

```jsonc
{
  "name": "on-order-created",
  "entry": "index.ts",
  "automations": [
    {
      "name": "On Order Created",
      "type": "entity",
      "entity_name": "Order",
      "event_types": ["create"],
      "description": "Run when a new order is created"
    },
    {
      "name": "On Order Update or Delete",
      "type": "entity",
      "entity_name": "Order",
      "event_types": ["update", "delete"]
    }
  ]
}
```

**Note:** `entity_name` must match the entity schema `name` in `base44/entities/` (e.g. entity file `order.jsonc` with `"name": "Order"` → use `"entity_name": "Order"`).

#### Entity hook payload

The function receives a JSON body with:

| Field | Description |
|-------|-------------|
| `event` | `{ type, entity_name, entity_id }` — event type, entity name, and record id |
| `data` | Current entity data. `null` if `payload_too_large` is true |
| `old_data` | Previous entity data (only for `"update"` events). `null` if `payload_too_large` is true or for create/delete |
| `payload_too_large` | `true` when entity data exceeded 200KB and was omitted. Use the Base44 SDK to fetch: `await base44.entities.<EntityName>.get(entity_id)` (or the dynamic API) to load the record. |

**Authentication / user identity:** When an automation runs (scheduled or entity hook), the request is authenticated as the **user who created the automation**, not as the user who performed the action. So `await base44.auth.me()` returns the automation creator. **There is no way to get the user who triggered the entity change** (e.g. who created, updated, or deleted the record). If you need to attribute actions, store a user reference on the entity (e.g. `created_by`, `updated_by`) and read it from `data` / `old_data` in the payload.

## Full Examples

### Daily CRON report

**base44/functions/daily-report/function.jsonc:**

```jsonc
{
  "name": "daily-report",
  "entry": "index.ts",
  "automations": [
    {
      "name": "Daily Report",
      "type": "scheduled",
      "schedule_mode": "recurring",
      "schedule_type": "cron",
      "cron_expression": "0 9 * * *",
      "is_active": true
    }
  ]
}
```

**base44/functions/daily-report/index.ts:**

```typescript
import { createClientFromRequest } from "npm:@base44/sdk";

Deno.serve(async (req) => {
  const base44 = createClientFromRequest(req);
  // Scheduled runs get auth context; use asServiceRole if you need full access
  const base44Admin = base44.asServiceRole;

  const orders = await base44Admin.entities.Orders.list({ limit: 100 });
  const summary = { total: orders.length, date: new Date().toISOString() };

  // e.g. send to Slack, email, or store in another entity
  return Response.json({ success: true, summary });
});
```

### Entity hook: on order created

**base44/functions/on-order-created/function.jsonc:**

```jsonc
{
  "name": "on-order-created",
  "entry": "index.ts",
  "automations": [
    {
      "name": "On Order Created",
      "type": "entity",
      "entity_name": "Order",
      "event_types": ["create"],
      "is_active": true
    }
  ]
}
```

**base44/functions/on-order-created/index.ts:**

```typescript
import { createClientFromRequest } from "npm:@base44/sdk";

Deno.serve(async (req) => {
  const base44 = createClientFromRequest(req);
  const payload = await req.json();
  const { event, data, old_data, payload_too_large } = payload;

  // event: { type, entity_name, entity_id }
  const entityId = event.entity_id;
  const eventType = event.type;

  // If payload was too large, data/old_data are null — fetch via SDK
  let current = data;
  if (payload_too_large && eventType !== "delete") {
    current = await base44.asServiceRole.entities.Orders.get(entityId);
  }

  // e.g. send confirmation email on create, or compare old_data vs data on update
  return Response.json({ success: true, orderId: entityId, eventType });
});
```

### Weekly cleanup (simple schedule)

**base44/functions/weekly-cleanup/function.jsonc:**

```jsonc
{
  "name": "weekly-cleanup",
  "entry": "index.ts",
  "automations": [
    {
      "name": "Weekly Cleanup",
      "type": "scheduled",
      "schedule_mode": "recurring",
      "schedule_type": "simple",
      "repeat_unit": "weeks",
      "repeat_interval": 1,
      "repeat_on_days": [1],
      "start_time": "02:00",
      "description": "Every Monday at 2:00"
    }
  ]
}
```

## Common Patterns

| Pattern | Use | Automation type |
|--------|-----|------------------|
| Daily report / digest | Email or Slack at 9am | CRON with `cron_expression`: `0 9 * * *` |
| On new record | Notify, sync, or validate when entity is created | Entity hook with `event_types`: `["create"]` |
| On update/delete | Audit, cache invalidation, or cleanup | Entity hook with `event_types`: `["update"]` or `["delete"]` |
| Weekly job | Cleanup or aggregation every Monday | Simple with `repeat_unit`: `"weeks"`, `repeat_on_days`: `[1]` |
| One-time run | Launch task or migration at a fixed time | One-time with `one_time_date` |

## Deploying

Automations are deployed with their function. There is no separate automation deploy command.

```bash
npx base44 functions deploy
```

This deploys all functions in `base44/functions/` and their `automations` arrays. For more on deployment, see [functions-deploy.md](functions-deploy.md).

## Common Mistakes

| Wrong | Correct | Why |
|-------|---------|-----|
| `entity_name: "order"` when schema name is `Order` | `entity_name: "Order"` | Entity name must match schema `name` exactly |
| `event_types: []` or missing | `event_types: ["create"]` (at least one) | At least one event type is required for entity hooks |
| Assuming `base44.auth.me()` is the user who triggered the entity change | Use `data` / `old_data` (e.g. `created_by`, `updated_by`) if you need who did the action | In automations, `auth.me()` is the user who **created the automation**. The triggering user is not available. |
| `schedule_type: "cron"` without `cron_expression` | Always set `cron_expression` for cron | Cron schedules require a valid cron expression |
| Putting automations in a separate file | Put `automations` inside `function.jsonc` | Automations are part of the function config |
| Expecting a separate `base44 automations deploy` | Use `npx base44 functions deploy` | Automations deploy with the function |