docs(skill): document sendNotification action (7 actions total) + CLI support

- skill: SKILL.md (7 actions in description + routing table entry), action-types.md
  (new section #4 sendNotification: config keys, variables, system-in-app semantics),
  automation-guide.md/cli-reference.md (--to-user/--title/--message/--severity/--path),
  development.md (7 actions), metadata.json abstract
- cli: action add --type sendNotification now builds config from granular flags
  (toUserId/title/message/severity/path); ACTION_TYPES includes sendNotification;
  live-verified via workflow create + action add + delete
This commit is contained in:
yeuimu
2026-08-17 07:50:15 +00:00
parent 3a03e0753c
commit 146d62c80b
8 changed files with 76 additions and 12 deletions
+4 -4
View File
@@ -4,8 +4,8 @@ description: >-
Operate a deployed inkreach-teable instance (a Teable fork with a self-built Operate a deployed inkreach-teable instance (a Teable fork with a self-built
automation engine). Configure tables, fields, records, views, and automations automation engine). Configure tables, fields, records, views, and automations
(8 triggers incl. recordCreated/Updated/Condition, formSubmitted, scheduledTime, (8 triggers incl. recordCreated/Updated/Condition, formSubmitted, scheduledTime,
buttonClick, webhook; 6 actions: script, sendEmail, httpRequest, createRecord, buttonClick, webhook; 7 actions: script, sendEmail, httpRequest, createRecord,
updateRecord, getRecords), plus secrets, execution history, and dynamic plugins updateRecord, getRecords, sendNotification), plus secrets, execution history, and dynamic plugins
(install/uninstall, base-level mount nodes, developer whitelist, CSP apiOrigins). (install/uninstall, base-level mount nodes, developer whitelist, CSP apiOrigins).
Trigger when the user wants to manage tables/fields/records/views, build or Trigger when the user wants to manage tables/fields/records/views, build or
configure automations/workflows, set up button-field triggers, schedule jobs, configure automations/workflows, set up button-field triggers, schedule jobs,
@@ -69,7 +69,7 @@ Respond in the user's language. Keep answers concise and action-oriented.
| Receive external HTTP | Trigger `webhook`; fire via `fire webhook` | Expecting auth (backend ignores it) | | Receive external HTTP | Trigger `webhook`; fire via `fire webhook` | Expecting auth (backend ignores it) |
| Schedule recurring job | Trigger `scheduledTime` (only type+interval work) | Passing triggerTime/weekdays (backend ignores) | | Schedule recurring job | Trigger `scheduledTime` (only type+interval work) | Passing triggerTime/weekdays (backend ignores) |
| Per-row AI / transformation | Action `script` reading `triggerInput` | Manual row-by-row via record API | | Per-row AI / transformation | Action `script` reading `triggerInput` | Manual row-by-row via record API |
| Send notification | Action `sendEmail` or `httpRequest` | — | | Send notification | Action `sendNotification` (system in-app) | `sendEmail` (needs SMTP) unless email is truly required |
| Add a custom UI / view / panel | Plugins: `plugin install --position base` | Manually editing DB rows | | Add a custom UI / view / panel | Plugins: `plugin install --position base` | Manually editing DB rows |
| Allow a user to upload plugins | Plugins: `plugin dev allow <userIdOrEmail>` (admin only) | — | | Allow a user to upload plugins | Plugins: `plugin dev allow <userIdOrEmail>` (admin only) | — |
| Plugin needs external API access | Plugins: declare `apiOrigins` in `plugin.json` manifest | Editing CSP in next.config.js (global) | | Plugin needs external API access | Plugins: declare `apiOrigins` in `plugin.json` manifest | Editing CSP in next.config.js (global) |
@@ -152,7 +152,7 @@ These differ from official teable and from the (stale) `docs/automation/triggers
Files in `api-reference/`, read when you need exact config formats: Files in `api-reference/`, read when you need exact config formats:
- **[trigger-types.md](api-reference/trigger-types.md)** — all 8 triggers: type string, config keys, output variables. - **[trigger-types.md](api-reference/trigger-types.md)** — all 8 triggers: type string, config keys, output variables.
- **[action-types.md](api-reference/action-types.md)** — all 6 actions: config keys, sandbox globals, variable references. - **[action-types.md](api-reference/action-types.md)** — all 7 actions: config keys, sandbox globals, variable references.
- **[field-types.md](api-reference/field-types.md)** — Teable field types, aliases, and option shapes (incl. Button field with `workflowId`). - **[field-types.md](api-reference/field-types.md)** — Teable field types, aliases, and option shapes (incl. Button field with `workflowId`).
## 7. Instance Access ## 7. Instance Access
@@ -1,13 +1,13 @@
# Action Types Reference # Action Types Reference
All 6 actions of the inkreach-teable automation engine. Actions run in topological order after the trigger; each receives the merged upstream output. All 7 actions of the inkreach-teable automation engine. Actions run in topological order after the trigger; each receives the merged upstream output.
An action node: An action node:
```json ```json
{ {
"id": "node-2", "id": "node-2",
"type": "action", "type": "action",
"category": "<one of the 6 types below>", "category": "<one of the 7 types below>",
"config": { ... }, "config": { ... },
"name": null "name": null
} }
@@ -158,11 +158,40 @@ inkreach-teable action add <wfId> --type httpRequest \
- GET/HEAD do not send a body. - GET/HEAD do not send a body.
**Output:** `{ "statusCode": 200, "headers": {...}, "body": <parsed> }` **Output:** `{ "statusCode": 200, "headers": {...}, "body": <parsed> }`
- Non-2xx still returns output but the node status is `failed`.
--- ---
## 4. createRecord — Create records ## 4. sendNotification — System in-app notification (站内信,非邮件)
```bash
inkreach-teable action add <wfId> --type sendNotification \
--to-user usr4ioKJl6XpZgyFhxW \
--title '新工单' --message '工单 {{n0.record.id}} 已创建' \
--severity info
```
**Config:**
```json
{
"toUserId": "usr4ioKJl6XpZgyFhxW",
"title": "新工单",
"message": "工单 {{n0.record.id}} 已创建",
"path": "/base/bseX/table/tblY",
"severity": "info"
}
```
- `toUserId`: recipient user ID (required). Can reference the trigger user with `{{n0.user.id}}` (submitter/operator — only populated on user-initiated triggers; scheduled/webhook resolve to empty).
- `title` + `message`: notification text; both support `{{nodeId.path}}` variables. If title set, rendered as `title\nmessage`.
- `path` (optional): click-through URL in the notification center.
- `severity`: `info` (default) | `warning` | `critical`.
**IMPORTANT**: this is a **system in-app notification** (bell badge + notification center + realtime socket push). It calls `NotificationService.sendCommonNotify` with `type=system` and **no email config — no email is sent**. Prefer it over `sendEmail` unless an actual email is required.
**Output:** `{ "sentCount": 1, "invalidUserIds": [], "toUserId": "usr..." }`
---
## 5. createRecord — Create records
```bash ```bash
inkreach-teable action add <wfId> --type createRecord \ inkreach-teable action add <wfId> --type createRecord \
@@ -184,7 +213,7 @@ inkreach-teable action add <wfId> --type createRecord \
--- ---
## 5. updateRecord — Update records ## 6. updateRecord — Update records
```bash ```bash
inkreach-teable action add <wfId> --type updateRecord \ inkreach-teable action add <wfId> --type updateRecord \
@@ -206,7 +235,7 @@ inkreach-teable action add <wfId> --type updateRecord \
--- ---
## 6. getRecords — Query records ## 7. getRecords — Query records
```bash ```bash
inkreach-teable action add <wfId> --type getRecords \ inkreach-teable action add <wfId> --type getRecords \
@@ -63,6 +63,7 @@ Full config details: [trigger-types.md](../api-reference/trigger-types.md).
| Create records | `createRecord` | `--target-table <id>`, `--records <json>` | | Create records | `createRecord` | `--target-table <id>`, `--records <json>` |
| Update records | `updateRecord` | `--target-table <id>`, `--records <json>` | | Update records | `updateRecord` | `--target-table <id>`, `--records <json>` |
| Query records | `getRecords` | `--target-table <id>`, `--query <json>` | | Query records | `getRecords` | `--target-table <id>`, `--query <json>` |
| Send system notification (站内信) | `sendNotification` | `--to-user <usrId>`, `--title`, `--message`, `--severity`, `--path` |
Full config details: [action-types.md](../api-reference/action-types.md). Full config details: [action-types.md](../api-reference/action-types.md).
@@ -123,6 +123,7 @@ Per-type options:
| `createRecord` | `--target-table <id>`, `--records <json>` | | `createRecord` | `--target-table <id>`, `--records <json>` |
| `updateRecord` | `--target-table <id>`, `--records <json>` | | `updateRecord` | `--target-table <id>`, `--records <json>` |
| `getRecords` | `--target-table <id>`, `--query <json>` | | `getRecords` | `--target-table <id>`, `--query <json>` |
| `sendNotification` | `--to-user <usrId>`, `--title <s>`, `--message <s>`, `--severity <s>`, `--path <s>` |
Details: [action-types.md](../api-reference/action-types.md). Details: [action-types.md](../api-reference/action-types.md).
@@ -117,7 +117,7 @@ CLI for automations. See [SKILL.md § Key Constraints](../SKILL.md#3-key-constra
Automation E2E tests live in `scripts/automation-test/`: Automation E2E tests live in `scripts/automation-test/`:
```bash ```bash
node scripts/automation-test/run-all.js # 59 cases: 8 triggers + 6 actions + cross-features node scripts/automation-test/run-all.js # 59 cases: 8 triggers + 7 actions + cross-features
node scripts/stress-test/stress-test.js # concurrency stress test node scripts/stress-test/stress-test.js # concurrency stress test
``` ```
Lib framework: `scripts/automation-test/lib.js`. Uses Node `http` (not fetch) Lib framework: `scripts/automation-test/lib.js`. Uses Node `http` (not fetch)
+1 -1
View File
@@ -3,7 +3,7 @@
"organization": "inkreach", "organization": "inkreach",
"authors": ["inkreach"], "authors": ["inkreach"],
"tags": ["database", "teable", "no-code", "automation", "self-hosted"], "tags": ["database", "teable", "no-code", "automation", "self-hosted"],
"abstract": "Operate a deployed inkreach-teable instance — configure tables, fields, records, views, and the self-built automation engine (8 triggers + 6 actions), plus development/deployment knowledge. Uses the inkreach-teable CLI which targets the project's own automation contract (not official teable CLI compatible).", "abstract": "Operate a deployed inkreach-teable instance — configure tables, fields, records, views, and the self-built automation engine (8 triggers + 7 actions), plus development/deployment knowledge. Uses the inkreach-teable CLI which targets the project's own automation contract (not official teable CLI compatible).",
"engines": { "engines": {
"inkreachTeableCli": ">=0.1" "inkreachTeableCli": ">=0.1"
}, },
+19
View File
@@ -367,6 +367,7 @@ const ACTION_TYPES = [
'createRecord', 'createRecord',
'updateRecord', 'updateRecord',
'getRecords', 'getRecords',
'sendNotification',
]; ];
function actionCommand() { function actionCommand() {
const cmd = new commander_1.Command('action'); const cmd = new commander_1.Command('action');
@@ -390,6 +391,11 @@ function actionCommand() {
.option('--target-table <id>', 'Target table id (createRecord/updateRecord/getRecords)') .option('--target-table <id>', 'Target table id (createRecord/updateRecord/getRecords)')
.option('--records <json>', 'Records JSON array (createRecord/updateRecord)') .option('--records <json>', 'Records JSON array (createRecord/updateRecord)')
.option('--query <json>', 'Query JSON (getRecords)') .option('--query <json>', 'Query JSON (getRecords)')
.option('--to-user <id>', 'Recipient user id (sendNotification)')
.option('--title <s>', 'Notification title (sendNotification)')
.option('--message <s>', 'Notification message (sendNotification)')
.option('--severity <s>', 'Notification severity info|warning|critical (sendNotification)')
.option('--path <s>', 'Click-through path, e.g. /base/xx/table/yy (sendNotification)')
.option('--name <n>', 'Optional node display name') .option('--name <n>', 'Optional node display name')
.option('--base-id <id>', 'Base id (overrides default)') .option('--base-id <id>', 'Base id (overrides default)')
.action((0, ctx_1.run)(async (ctx, args, o) => { .action((0, ctx_1.run)(async (ctx, args, o) => {
@@ -606,6 +612,19 @@ function buildActionConfig(opts) {
config.query = JSON.parse(opts.query); config.query = JSON.parse(opts.query);
break; break;
} }
case 'sendNotification': {
if (opts.toUser)
config.toUserId = opts.toUser;
if (opts.title)
config.title = opts.title;
if (opts.message)
config.message = opts.message;
if (opts.severity)
config.severity = opts.severity;
if (opts.path)
config.path = opts.path;
break;
}
default: default:
break; break;
} }
+14
View File
@@ -417,6 +417,7 @@ const ACTION_TYPES = [
'createRecord', 'createRecord',
'updateRecord', 'updateRecord',
'getRecords', 'getRecords',
'sendNotification',
] as const; ] as const;
export function actionCommand(): Command { export function actionCommand(): Command {
@@ -445,6 +446,11 @@ export function actionCommand(): Command {
.option('--target-table <id>', 'Target table id (createRecord/updateRecord/getRecords)') .option('--target-table <id>', 'Target table id (createRecord/updateRecord/getRecords)')
.option('--records <json>', 'Records JSON array (createRecord/updateRecord)') .option('--records <json>', 'Records JSON array (createRecord/updateRecord)')
.option('--query <json>', 'Query JSON (getRecords)') .option('--query <json>', 'Query JSON (getRecords)')
.option('--to-user <id>', 'Recipient user id (sendNotification)')
.option('--title <s>', 'Notification title (sendNotification)')
.option('--message <s>', 'Notification message (sendNotification)')
.option('--severity <s>', 'Notification severity info|warning|critical (sendNotification)')
.option('--path <s>', 'Click-through path, e.g. /base/xx/table/yy (sendNotification)')
.option('--name <n>', 'Optional node display name') .option('--name <n>', 'Optional node display name')
.option('--base-id <id>', 'Base id (overrides default)') .option('--base-id <id>', 'Base id (overrides default)')
.action( .action(
@@ -652,6 +658,14 @@ export function buildActionConfig(opts: Record<string, string>): Record<string,
if (opts.query) config.query = JSON.parse(opts.query); if (opts.query) config.query = JSON.parse(opts.query);
break; break;
} }
case 'sendNotification': {
if (opts.toUser) config.toUserId = opts.toUser;
if (opts.title) config.title = opts.title;
if (opts.message) config.message = opts.message;
if (opts.severity) config.severity = opts.severity;
if (opts.path) config.path = opts.path;
break;
}
default: default:
break; break;
} }