diff --git a/README.md b/README.md index 7bd762d..8e5d6fc 100644 --- a/README.md +++ b/README.md @@ -47,6 +47,29 @@ Rotate any of these by editing `.env` and restarting: If you need a checked-in template, create `.env.example` with the keys but no values. +## Workflows (version-controlled here) + +Importable workflow JSON lives in `workflows/`. The live workflows are +stored in the n8n volume; these files are the reviewable, git-tracked +source. Import via the UI (Workflows → Import from File) or +`POST /api/v1/workflows` with an `X-N8N-API-KEY` header. + +| File | Purpose | +|-----------------------------------|----------------------------------------------------------------| +| `workflows/wiki-compile-nudge.json` | Daily check that nudges Google Chat when the wiki-vault is due for a compile (≥10 new sources, or ≥7 days stale). Schedule → Postgres drift query against `petalbrain` → IF → Google Chat HTTP POST. | + +**`wiki-compile-nudge` — before it runs:** + +- Fill two placeholders after import: the **Postgres credential** (select + the existing `petalbrain` cred) and the **Google Chat space webhook URL** + in the HTTP node. +- Depends on a `wiki.compile_runs` table in `petalbrain` + (`id bigserial`, `compiled_at timestamptz default now()`) and the + wiki-maintenance compile writing a row to it on each run — the drift + query reads `max(compiled_at)` as its "last compile" baseline. +- The drift logic is in SQL (returns a `should_notify` boolean), so the + IF node just checks that flag. + ## Persistence — external volume ``` diff --git a/workflows/wiki-compile-nudge.json b/workflows/wiki-compile-nudge.json new file mode 100644 index 0000000..a9840d1 --- /dev/null +++ b/workflows/wiki-compile-nudge.json @@ -0,0 +1,85 @@ +{ + "name": "wiki-compile-nudge", + "nodes": [ + { + "parameters": { + "rule": { + "interval": [ + { "field": "cronExpression", "expression": "7 20 * * *" } + ] + } + }, + "id": "schedule-trigger", + "name": "Daily @ 20:07", + "type": "n8n-nodes-base.scheduleTrigger", + "typeVersion": 1.2, + "position": [260, 300] + }, + { + "parameters": { + "operation": "executeQuery", + "query": "WITH last AS (\n SELECT COALESCE(max(compiled_at), 'epoch') AS ts FROM wiki.compile_runs\n),\nn AS (\n SELECT count(*) AS c FROM wiki.artifacts WHERE created_at > (SELECT ts FROM last)\n)\nSELECT\n (SELECT c FROM n) AS new_sources,\n EXTRACT(day FROM now() - (SELECT ts FROM last))::int AS days_since,\n (\n (SELECT c FROM n) >= 10\n OR (EXTRACT(day FROM now() - (SELECT ts FROM last)) >= 7 AND (SELECT c FROM n) >= 1)\n ) AS should_notify;", + "options": {} + }, + "id": "postgres-drift", + "name": "Drift query (petalbrain)", + "type": "n8n-nodes-base.postgres", + "typeVersion": 2.5, + "position": [480, 300], + "credentials": { + "postgres": { "id": "REPLACE_WITH_PETALBRAIN_CRED_ID", "name": "Petalbrain Postgres" } + } + }, + { + "parameters": { + "conditions": { + "options": { "caseSensitive": true, "typeValidation": "strict", "version": 2 }, + "combinator": "and", + "conditions": [ + { + "leftValue": "={{ $json.should_notify }}", + "rightValue": true, + "operator": { "type": "boolean", "operation": "true", "singleValue": true } + } + ] + }, + "options": {} + }, + "id": "if-should-notify", + "name": "Compile due?", + "type": "n8n-nodes-base.if", + "typeVersion": 2, + "position": [700, 300] + }, + { + "parameters": { + "method": "POST", + "url": "REPLACE_WITH_GOOGLE_CHAT_SPACE_WEBHOOK_URL", + "sendBody": true, + "specifyBody": "json", + "jsonBody": "={\n \"text\": \"\\ud83c\\udf3f Wiki compile due \\u2014 {{ $json.new_sources }} new sources, {{ $json.days_since }}d since last compile.\\nRun: \\\"compile the wiki at /opt/projects/wiki-vault\\\"\"\n}", + "options": {} + }, + "id": "google-chat-notify", + "name": "Google Chat nudge", + "type": "n8n-nodes-base.httpRequest", + "typeVersion": 4.2, + "position": [920, 220] + } + ], + "connections": { + "Daily @ 20:07": { + "main": [[{ "node": "Drift query (petalbrain)", "type": "main", "index": 0 }]] + }, + "Drift query (petalbrain)": { + "main": [[{ "node": "Compile due?", "type": "main", "index": 0 }]] + }, + "Compile due?": { + "main": [ + [{ "node": "Google Chat nudge", "type": "main", "index": 0 }], + [] + ] + } + }, + "settings": { "executionOrder": "v1" } +}