n8n/scripts/instance-seeding/AGENTS.md

182 lines
8.1 KiB
Markdown
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# Seed n8n instance
`seedInstance.mjs` fills a local n8n instance with a realistic-looking spread of
projects, workflows, credentials, and data tables via the **public API**. The
resulting dependency graph is designed to render like a real org's automation
estate: dense intra-team clusters, sparse cross-team bridges through shared
utility projects, a few legacy "trenchcoat" projects sitting off to the side,
and one central data table that everything reaches through a proxy workflow.
Useful for demos, perf testing, visual QA of the workflow dependency graph, and
poking at the workflow-index module with non-trivial input.
## Quick start
```sh
N8N_API_KEY="<a public-api JWT for an owner/admin>" \
node scripts/instance-seeding/seedInstance.mjs
```
Targets `http://localhost:5678` by default. The script is **destructive by
default**: it deletes its own prior output (anything tagged `[seed]`) and any
team projects whose names match the current taxonomy plus orphans from older
runs. Personal-project entities that don't match the seed prefix are left
alone, as are the n8n-default `My project` team projects.
### Environment variables
| Var | Default | Purpose |
| --- | --- | --- |
| `N8N_API_KEY` | (required) | Public-API JWT. Must have owner or admin scopes. |
| `N8N_BASE_URL` | `http://localhost:5678` | n8n instance to seed. |
| `CLEAR` | `false` | Set to `true` to wipe data instead. |
| `PERSONAL_WORKFLOWS` | `50` | Amount of workflows to create in the personal project. |
Runtime is ~3045 s for a default run (~500 workflows, ~30 projects).
## What it creates
**Projects** (30 team projects + your existing personal):
- **2 utility projects** — `Shared Platform` (technical plumbing: Audit
Logger, Slack Alerts Dispatcher, Sentry Error Forwarder, …) and
`Org Utilities` (business helpers: Tenant Resolver, Vault Reader, Feature
Flag Resolver, …). These are the hub workflows the rest of the org calls
into.
- **25 community projects** organised into 5 themed communities of 5 projects
each: Revenue, Customer, Engineering, Operations, Knowledge.
- **3 trenchcoat projects** — Legacy Migrations, Skunkworks, Founder's
Workflows. Smaller, internally split into 2-3 disjoint sub-systems (e.g.
`[HR System]`, `[Old Billing]`, `[Acme Acquisition]`), and almost entirely
detached from the rest of the org. They model accreted legacy state.
**Credentials** (~110):
- Two per project max (random recipes: Notion, Slack, Postgres, GitHub, …).
- Plus **5 global credentials** living in the utility projects (Production
Slack Webhook, Datadog API, GitHub platform bot, OpenAI production,
Vault read-only).
**Data tables** (~1520):
- One per ~55% of projects, with 520 sample rows.
- Plus one **central data table** `seed_customers` in `Org Utilities` that
the entire org reaches through a single proxy workflow.
**Workflows** (~500), built in four phases:
- **Phase 0** — Utility lynchpin workflows in `Shared Platform` and
`Org Utilities`, plus the Customers Proxy.
- **Phase 1** — Leaf workflows in every project, no sub-calls.
- **Phase 2** — Parent workflows with sub-workflow refs. Community projects
pick own/sibling/lynchpin; trenchcoats pick within their internal group.
- **Phase 3** — Data-table consumer workflows (one per project DT).
- **Phase 4** — Cross-project data-table proxies for ~6 non-utility DTs.
## Two non-obvious architectural rules
1. **`DataTable` nodes can only point at tables in their own project.** Cross-
project access goes through a proxy workflow. The `customersProxy` in
`Org Utilities` is the only workflow with a direct `DataTable` node on
the central table; everyone else calls the proxy via `ExecuteWorkflow`.
Phase 4 generalises this pattern to ~6 other data tables.
2. **Per-project external-ref budgets.** Each community project is capped at
25 distinct external workflow refs and 510 external credential refs,
tracked across all phases. About a third of community projects opt out of
utility refs entirely (some of those go fully self-contained — no
external refs of any kind). Trenchcoats and utility projects are exempt.
## Tunable knobs
All knobs live at the top of `seedInstance.mjs`. The ones that change the
shape of the graph the most:
| Constant | Effect |
| --- | --- |
| `COMMUNITIES` | Project taxonomy. Add/remove communities or projects. |
| `TRENCHCOAT_PROJECTS` + `TRENCHCOAT_GROUPS` | Legacy projects and their internal subsystems. |
| `UTILITY_WORKFLOW_THEMES` | Lynchpin workflow names per utility project. |
| `LYNCHPIN_CRED_RECIPES` | The 5 global credentials. |
| `UTILITY_REF_PROB` (0.6) | Per-workflow probability of including a utility ref. |
| `CENTRAL_DT_REF_PROB` (0.08) | Per-workflow probability of calling the Customers Proxy (indirect central-DT use). |
| `ORG_UTIL_DIRECT_DT_PROB` (0.5) | Per-workflow probability that an Org Utilities phase-0 workflow gets a direct DataTable node on the central table. |
| `EXT_WF_REF_BUDGET` / `EXT_CRED_REF_BUDGET` | Per-project distinct-ref caps. |
| `NON_UTILITY_USING_TARGET` (9) | How many community projects opt out of utility refs. |
| `SELF_CONTAINED_PROJECT_PROB` | Subset of the opt-out projects that go fully siloed. |
| `sampleWorkflowCount()` | Power-law-ish size buckets per project kind. |
`SUBWF_PROB_OWN`/`_SIBLING`/`_LYNCHPIN` (in `pickCommunitySubWf`) govern how
parent workflows route sub-calls.
## Verifying a run
The dependency-graph endpoint is the canonical view of what the seed
produced. It includes both the community structure and the central-DT proxy
pattern:
```sh
curl -s "$N8N_BASE_URL/api/v1/workflows/dependency-graph?format=dot" \
-H "X-N8N-API-KEY: $N8N_API_KEY" | sfdp -Tsvg -Goverlap=prism > graph.svg
```
`sfdp`/`fdp` (Graphviz force-directed layouts) reveal the cluster topology
better than the default hierarchical `dot` layout.
Counts via API:
```sh
for path in workflows projects credentials data-tables; do
echo -n "$path: "
curl -s "$N8N_BASE_URL/api/v1/$path?limit=1" \
-H "X-N8N-API-KEY: $N8N_API_KEY" | jq -r '.data | length'
done
```
Key numbers a default run should land near:
- ~500 workflows, 30 team projects, ~110 credentials, ~15 data tables
- ~45% of workflows reference a utility workflow
- ~510% of workflows reach the central data table (24 direct refs from
workflows inside Org Utilities — Customers Proxy plus a few service
workflows like Region Router or Feature Flag Resolver — and the rest via
`ExecuteWorkflow` into the proxy)
- 20 of 29 non-utility projects use utility workflows
- 0 direct cross-project DataTable references (architectural invariant)
## Re-running and cleanup
The clear step is greedy: any workflow / credential / data-table with the
`[seed]` (or `seed_` for data tables) prefix is deleted, plus any team
project owning a `[seed]`-prefixed entity, plus any orphan team project from
an earlier run that doesn't match the current `PROJECT_NAMES` list and is
empty and not named `My project`.
To remove all seeded data without reseeding:
```sh
N8N_API_KEY=CLEAR=only node bin/seedInstance/seedInstance.mjs
```
## Adding new behaviour
Adding a new shape of workflow usually means three places:
1. A constant or recipe at the top of the file (theme name, cred type, …).
2. A change inside `workflowNodes()` if it needs a new node type.
3. A phase change (or new phase) inside `main()` that calls `createWf()`.
`applyOrgUtilityRefs()` is the central hook for "every workflow should
sometimes touch X". Phase 4 (`/* cross-project data-table proxies */`) is
the template for "select a few entities, give each its own consumer
fan-out".
## Known limitations
- Trenchcoat phase-3 (data-table consumer) workflows don't carry an internal
group label, so they show up as ungrouped within their trenchcoat project.
Minor visual artifact only.
- The `[seed] X: [group] Y N` naming convention is what powers the
group-aware visualisation. Renaming a workflow externally severs the
link the analyser uses to group it.
- No protection against running against a non-local instance. **Don't point
it at a shared/production n8n** — the clear step will delete everything
prefixed `[seed]` regardless of who created it.