The automation module stores named rules made of a free-form trigger object and a free-form action object in the AutomationRule table (automation_rules). It is storage only. Nothing in apps/core-api reads these rows to run them: the only other reference to prisma.automationRule in the backend is the demo seed script in packages/db/scripts/seed-demo/ops.ts. The automations that actually execute are separate modules:

Mount point and auth

Source: apps/core-api/src/modules/automation/. The router adds no role guard, so any role the gateway forwards in x-user-role can call every endpoint. Each query is scoped to req.auth.studioId. A request without a studio in its auth context gets UNAUTHORIZED (401). The path /v1/automation without the web segment is a different router (automationApiRouter, API key auth) and is not covered here.

The rule object

All endpoints return the Prisma row as stored.
string
cuid.
string
Owning studio. Always taken from the auth context, never from the body.
string
Display name.
object
Free-form JSON. The schema is z.record(z.string(), z.unknown()), so any keys are accepted.
object
Free-form JSON, same rule as trigger.
boolean
Defaults to true.
string
ISO timestamp.
string
ISO timestamp.

Endpoints

GET /v1/web/automation

Lists the studio’s rules, newest first (createdAt descending). Auth: web lane, any role.
boolean
Filter by the enabled flag. Parsed with z.coerce.boolean(), which treats any non-empty string as true. enabled=false therefore filters for enabled rules. Omit the parameter to get both.
integer
default:"1"
Positive integer.
integer
default:"20"
Positive integer, maximum 500.
Response: data holds the page plus the total count for the filter.
The trigger and action values in the example are illustrative. The API does not define or validate their keys. Errors: VALIDATION (422) for a bad query, UNAUTHORIZED (401).

POST /v1/web/automation

Creates a rule. Responds with status 201. Auth: web lane, any role.
string
required
At least 1 character.
object
required
Any JSON object.
object
required
Any JSON object.
boolean
default:"true"
Whether the rule is on.
Response: the created rule object. Errors: VALIDATION (422), UNAUTHORIZED (401).

GET /v1/web/automation/:id

Returns one rule. The lookup is findFirst on id and studioId, so a rule in another studio reads as missing. Auth: web lane, any role.
string
required
Rule id.
Response: the rule object. Errors: NOT_FOUND (404) with message automation rule not found.

PATCH /v1/web/automation/:id

Updates the fields present in the body. trigger and action are replaced whole when sent, not merged. Auth: web lane, any role.
string
required
Rule id.
string
At least 1 character.
object
Replaces the stored trigger.
object
Replaces the stored action.
boolean
Turn the rule on or off.
Response: the updated rule object. Errors: NOT_FOUND (404), VALIDATION (422).

DELETE /v1/web/automation/:id

Deletes the rule after checking it belongs to the studio. Responds with status 204 and no body. Auth: web lane, any role.
string
required
Rule id.
Errors: NOT_FOUND (404).

Notes for maintainers

  • The service checks ownership with get(studioId, id) and then calls repo.update(id, ...) or repo.remove(id) by id alone. The check and the write are two statements, not one scoped write.
  • There are no side effects: no jobs, notifications or audit rows are written.