115 lines
4.1 KiB
JSON
115 lines
4.1 KiB
JSON
{
|
|
"name": "Bettersight — Embedding + Comparable Matching (Sunday night)",
|
|
"nodes": [
|
|
{
|
|
"parameters": {
|
|
"rule": {
|
|
"interval": [{ "field": "cronExpression", "expression": "0 23 * * 0" }]
|
|
}
|
|
},
|
|
"id": "schedule-trigger",
|
|
"name": "Schedule Trigger (Sunday 23:00)",
|
|
"type": "n8n-nodes-base.scheduleTrigger",
|
|
"typeVersion": 1.2,
|
|
"position": [0, 0]
|
|
},
|
|
{
|
|
"parameters": {
|
|
"method": "GET",
|
|
"url": "={{ $env.POCKETBASE_URL }}/api/collections/tenants/records",
|
|
"sendQuery": true,
|
|
"queryParameters": {
|
|
"parameters": [
|
|
{ "name": "filter", "value": "status = 'active' || status = 'trial'" },
|
|
{ "name": "perPage", "value": "200" }
|
|
]
|
|
},
|
|
"authentication": "genericCredentialType",
|
|
"genericAuthType": "httpHeaderAuth"
|
|
},
|
|
"id": "list-active-tenants",
|
|
"name": "List active tenants (PocketBase)",
|
|
"type": "n8n-nodes-base.httpRequest",
|
|
"typeVersion": 4.2,
|
|
"position": [220, 0],
|
|
"credentials": {
|
|
"httpHeaderAuth": { "id": "pocketbase-admin-auth", "name": "PocketBase Admin Auth" }
|
|
}
|
|
},
|
|
{
|
|
"parameters": { "fieldToSplitOut": "items" },
|
|
"id": "split-tenants",
|
|
"name": "Split into items",
|
|
"type": "n8n-nodes-base.splitOut",
|
|
"typeVersion": 1,
|
|
"position": [440, 0]
|
|
},
|
|
{
|
|
"parameters": { "batchSize": 1 },
|
|
"id": "loop-tenants",
|
|
"name": "Loop Over Tenants",
|
|
"type": "n8n-nodes-base.splitInBatches",
|
|
"typeVersion": 3,
|
|
"position": [660, 0]
|
|
},
|
|
{
|
|
"parameters": {
|
|
"method": "POST",
|
|
"url": "={{ $env.BETTERSIGHT_API_BASE_URL }}/internal/embed-products/{{ $json.id }}",
|
|
"sendHeaders": true,
|
|
"headerParameters": {
|
|
"parameters": [{ "name": "X-API-Key", "value": "={{ $env.API_SECRET_KEY }}" }]
|
|
}
|
|
},
|
|
"id": "embed-products",
|
|
"name": "POST /internal/embed-products/{tenant_id}",
|
|
"type": "n8n-nodes-base.httpRequest",
|
|
"typeVersion": 4.2,
|
|
"position": [880, 0]
|
|
},
|
|
{
|
|
"parameters": {
|
|
"method": "POST",
|
|
"url": "={{ $env.BETTERSIGHT_API_BASE_URL }}/internal/match-comparable/{{ $('Loop Over Tenants').item.json.id }}",
|
|
"sendHeaders": true,
|
|
"headerParameters": {
|
|
"parameters": [{ "name": "X-API-Key", "value": "={{ $env.API_SECRET_KEY }}" }]
|
|
}
|
|
},
|
|
"id": "match-comparable",
|
|
"name": "POST /internal/match-comparable/{tenant_id}",
|
|
"type": "n8n-nodes-base.httpRequest",
|
|
"typeVersion": 4.2,
|
|
"position": [1100, 0]
|
|
}
|
|
],
|
|
"connections": {
|
|
"Schedule Trigger (Sunday 23:00)": {
|
|
"main": [[{ "node": "List active tenants (PocketBase)", "type": "main", "index": 0 }]]
|
|
},
|
|
"List active tenants (PocketBase)": {
|
|
"main": [[{ "node": "Split into items", "type": "main", "index": 0 }]]
|
|
},
|
|
"Split into items": {
|
|
"main": [[{ "node": "Loop Over Tenants", "type": "main", "index": 0 }]]
|
|
},
|
|
"Loop Over Tenants": {
|
|
"main": [
|
|
[],
|
|
[{ "node": "POST /internal/embed-products/{tenant_id}", "type": "main", "index": 0 }]
|
|
]
|
|
},
|
|
"POST /internal/embed-products/{tenant_id}": {
|
|
"main": [[{ "node": "POST /internal/match-comparable/{tenant_id}", "type": "main", "index": 0 }]]
|
|
},
|
|
"POST /internal/match-comparable/{tenant_id}": {
|
|
"main": [[{ "node": "Loop Over Tenants", "type": "main", "index": 0 }]]
|
|
}
|
|
},
|
|
"active": false,
|
|
"settings": { "executionOrder": "v1" },
|
|
"meta": {
|
|
"description": "CLAUDE.md §19 Phase 6 task 51 — Sunday night, per active tenant: embed any un-embedded competitor products AND client_trips (POST /internal/embed-products), then run semantic comparable-trip matching (POST /internal/match-comparable). Order matters — match-comparable needs both sides already embedded. client_trips itself is populated continuously by every /research submission (embedding_service.save_client_trip()), not by this workflow. Not yet imported/run against a live n8n instance."
|
|
}
|
|
}
|