@noeva/etl-core
v1.0.1
Published
Code-first BI/ETL platform — Talend-style data integration in TypeScript
Readme
noeva-etl
Piattaforma code-first per applicazioni di Business Intelligence con forte componente
ETL (estrazione → trasformazione → caricamento), in stile Talend ma versionata, testata
e documentata come software: TypeScript, pnpm, vitest.
📄 Panoramica condivisibile del prodotto: Technical Overview.
Perché code-first
Le pipeline sono codice: versionabili, testabili, rivedibili in PR, riusabili. Niente job grafici opachi, niente lock-in. Vedi ADR-0002.
Quick start
pnpm install
pnpm run check # typecheck + lint + format + test:cov + gate delle versioni + gate dei changeset + build + API pubblica
# (report di api-extractor) + test del pacchetto + smoke del tarball + nessun cliente
# nel tarball + guida del core
# — lo stesso gate della CI, che gira sulle PR verso
# dev e main e sui push su main
pnpm run test:watch
pnpm run docs:dev # la guida del core in locale con etl docs dev (ADR-0043, ADR-0095 §5)
# CLI: elenca ed esegui le pipeline (legge le env da .env)
pnpm run etl list
pnpm run etl run orders-enriched-daily
# storico locale: ogni run conclusa lascia il suo report in .runs/ (ADR-0039),
# consultabile senza UI e senza rete
pnpm run etl runs list
pnpm run etl runs show <runId> # basta un prefisso non ambiguo
pnpm run etl runs list --pipeline orders-enriched-daily --limit 5
pnpm run etl runs show <runId> --json # report grezzo, per comporre con jq
# run tracciata: il percorso dei primi record di ogni source e dei loro derivati,
# con i valori in chiaro, in .runs/<runId>.trace.json (ADR-0088,
# docs/conventions/run-trace.md); --trace-max-records fissa il tetto (default 1000),
# --trace-max-errors quello dei record in errore fuori dal campione (default 1000)
pnpm run etl run orders-enriched-daily --trace --trace-sample 10
# stato di pipeline: i watermark delle source incrementali (ADR-0068). Locale in
# .state/, oppure quello del worker con --workspace <id> — vedi
# docs/runbooks/stato-incrementale.md
pnpm run etl state show <pipeline>
pnpm run etl state reset <pipeline> --node <id> --to <valore> --reason "<motivo>"
# ambiente: le variabili obbligatorie mancanti nell'intero catalogo, con chi le
# dichiara (core, istanza, pipeline), e le chiavi del .env che nessuno dichiara
# (ADR-0094 §1) — vedi docs/runbooks/aggiornamento-pm2.md
pnpm run etl env check
# conformità del catalogo (ADR-0093 §4): scopo dei nodi, changelog, piano senza
# credenziali e senza segreti (ambiente di prova da .env.example), cartelle orfane in
# src/pipelines/ — una riga per violazione, exit 1 se ce n'è una
pnpm run catalog:check
# sito di documentazione del repo (ADR-0095 §6), con tema e componenti dal pacchetto:
# si ferma su scheda o scopo mancante, link rotto o core: non risolto, una riga per
# problema — vedi docs/conventions/documentation.md
pnpm run docs:build
# versioni di pipeline (ADR-0086): lo snapshot del piano della versione corrente,
# calcolato senza .env — vedi docs/conventions/versioni-di-pipeline.md
pnpm run pipeline:snapshot <pipeline>
# il gate delle versioni: una pipeline cambiata rispetto a origin/dev (origin/main su
# hotfix/* verso main) vuole bump e voce — vedi docs/conventions/versioni-di-pipeline.md
pnpm run pipeline:check
# rollback di una pipeline sola a una versione andata in produzione: prepara un branch
# hotfix/* da origin/main, senza committare — vedi docs/runbooks/rollback-di-pipeline.md
pnpm run pipeline:rollback <pipeline> <N> --motivo "<testo>" --ticket <chiave>
# in un repo cliente: il boilerplate in una cartella vuota, il gate completo,
# lo stesso della CI, il kit dell'agente riscritto dal core installato, e
# l'aggiornamento del core: --check in sola lettura, poi il bump coi file gestiti
# (ADR-0094 §4–5) — vedi docs/GUIDA_SVILUPPO.md §2, §7 e §10
pnpm exec etl init <slug>
pnpm exec etl ci
pnpm exec etl agent sync
pnpm exec etl upgrade --check
pnpm exec etl upgrade
# daemon: polling continuo su processes (worker_type da env; uno o più workspace,
# NOEVA_WORKSPACE_IDS per il multi-workspace) — vedi docs/runbooks/etl-worker.md
pnpm run etl workerRequisiti: Node ≥ 26, pnpm 9.
Distribuzione (Docker / CLI)
Quello che si mette in servizio è un repo cliente a un commit, in due confezioni avviate
entrambe con etl serve (ADR-0094):
l'immagine container, costruita dal file gestito image.yml col Dockerfile del pacchetto
(@noeva/etl-core/deploy/Dockerfile) e pubblicata su GHCR con tag = SHA, oppure PM2 dai
sorgenti, con un ecosystem.config.cjs di una riga su @noeva/etl-core/pm2. Runbook:
Deploy e
Aggiornare un deploy PM2.
L'entrypoint è la CLI etl, che carica da sola il .env alla radice del repo; il resto della
config arriva da variabili d'ambiente. Tre modi di avviarla:
serve— ilCMDdi default dell'immagine: nello stesso processo espone i grafi via HTTP per la UI e avvia i worker (un poller suprocessesper workspace). Un solo container fa girare tutto (ADR-0028, runbook). Lancia anche le run tracciate chieste dall'app desktop sulla stessa macchina (ADR-0090).worker— solo i poller, senza server; utile per scalare i worker a parte, ma mai in parallelo a unservenello stesso ambiente, o i job vengono presi due volte (runbook). Il multi-workspace è la listaNOEVA_WORKSPACE_IDScon un'unicaNOEVA_API_KEYcondivisa (ADR-0021).run <pipeline>— batch: un container esegue una pipeline e termina. Con--tracesalva anche la traccia dei record (La traccia di una run).
Il Dockerfile alla radice di questo repo costruisce l'immagine del core, con le sue pipeline
d'esempio e pronte: serve a provarla in locale. L'immagine di un cliente si costruisce dal suo repo.
docker build -t noeva-etl .
docker run --rm --env-file .env -p 3005:3005 noeva-etl # serve: grafi + worker
docker run --rm noeva-etl list
docker run --rm --env-file .env noeva-etl run <pipeline>Il deploy su ECR di un cliente (ADR-0104) parte dal suo repo, con lo strumento del pacchetto:
etl deploy-ecr <cliente> (runbook). Nel core non resta nessun
cliente da deployare.
La UI (noeva-etl-ui) non passa da ECR: è un'app desktop Tauri, che si builda nel suo
submodule con pnpm tauri build (ADR-0025,
che supera ADR-0023). In sviluppo ./dev-desktop.sh avvia insieme etl serve e la finestra
Tauri.
Dettagli in docs/runbooks/deployment.md e ADR-0005.
Concetti (mappa Talend → codice)
| Talend | Qui | File |
| ------------------------------ | ------------------------------------------------------------------- | ----------------------------- |
| Componente input/output | Source<T> / Sink<T> | src/core/connector.ts |
| Trasformazione | Transform<I,O> | src/core/transform.ts |
| Lookup su DB o API | Nodo lookup (lettura, SQL o REST) | src/core/lookup.ts |
| Componente AI | Nodo ai (domanda a un modello) | src/core/ai.ts |
| Output con Main | Nodo action (scrittura per record) | src/core/action.ts |
| tXxxRow (senza dati) | Nodo task (operazione senza record: truncate, scambio di tabelle) | src/core/task.ts |
| OnSubjobOk | Edge di controllo (after su .task() e .source()) | src/core/control-flow.ts |
| Job / flusso | graph()...build() | src/core/graph-builder.ts |
| Schema componente | Contratto Zod + validate() | src/core/transform.ts |
| Context | RunContext | src/core/context.ts |
| Reject flow | Dead-letter sink (per nodo) | src/core/graph.ts |
| Try/catch (ramo) | Nodo try-catch + porta catch | src/core/graph.ts |
| tMap con più output | Nodo route (una porta per condizione) | src/core/route.ts |
| tUnite | Nodo union (fan-in, record invariati) | src/core/union.ts |
| tJoin | Nodo join (due flussi per chiave) | src/core/join.ts |
| tPostgresqlSCD / tMSSqlSCD | Sink SQL con mode: "scd2" | src/connectors/shared/scd2/ |
| tSystem | processoEsternoAction in un nodo action (programma senza shell) | src/connectors/process/ |
Le transform pronte della libreria (mapColumns, groupBy, dedup, explode, unpivot, pivot, sort, chunk, parse,
serialize, hashRow, surrogateKey, mask, profile, assert), con la corrispondenza Talend, sono nel catalogo di
docs/nodes/transform.md.
Esempio end-to-end (join, ramo catch, sub-pipeline): src/pipelines/orders-enriched-daily/.
Regole del progetto (da leggere)
- 📜 CLAUDE.md — regole operative vincolanti (test e doc obbligatori, Definition of Done).
- 🧭 docs/ — convenzioni, architettura, ADR, schede pipeline, runbook.
- 🧪 Test non opzionali: strategia di test.
- 📝 Documentazione come tassello fondante: policy.
Workflow dell'agente
Il kit dell'agente nasce in kit/ e etl agent sync lo copia in .claude/*/noeva-etl-*, qui come
in ogni repo cliente: le skill /new-pipeline, /new-connector, /new-transform, /etl-review,
/doc-sync ed etl-graph, i subagent di review e l'hook di guardia sui branch. Solo per il core:
la skill etl-core e il subagent project-pulse. Vedi CLAUDE.md §8.
Struttura
src/core/ framework ETL (testato, senza logica di dominio)
src/connectors/ connettori riusabili verso sistemi reali
src/transforms/ trasformazioni riusabili
src/pipelines/<n>/ solo cartelle di pipeline (schema, definizione, changelog, snapshot del piano, run, test)
src/catalog/ catalogo delle pipeline lanciabili (etl.config.ts, defineEtlConfig) e workspace-scope
src/versions/ versioni di pipeline (ADR-0086): changelog, snapshot del piano, gate, rollback
src/sub-pipelines/ sub-pipeline riusabili, istanziate dal nodo `pipeline` (ADR-0079)
src/runs/ storico locale delle run (RunStore, formattazione CLI) — mai importato da core/
src/state/ store dello stato di pipeline: memoria, file, noeva-server-api — mai importato da core/
src/worker/ daemon: poller su `processes` (claim, dispatch, loop)
src/docs/ `etl docs build|dev`: gate della documentazione, sito e guida del core installata (ADR-0095 §6)
src/init/ `etl init`: il boilerplate di un repo cliente dal template in kit/boilerplate/ (ADR-0094 §5)
src/ci/ `etl ci`: gli strumenti della toolchain lanciati dal gate di un repo cliente (ADR-0094 §4)
src/agent/ `etl agent sync`: il kit dell'agente copiato in .claude/*/noeva-etl-* e il blocco di AGENTS.md (ADR-0094 §5)
src/upgrade/ `etl upgrade`: registry, changelog fra due versioni, file gestiti e bump (ADR-0094 §5)
src/testing/ doppi in memoria dei sistemi esterni (IMAP, Noeva, SendGrid), subpath ./testing
src/contract.ts tipi del contratto fra `etl serve` e la UI (ADR-0095 §3), subpath ./contract
presets/ preset di tsconfig, ESLint e vitest esportati dal pacchetto, che il core estende (ADR-0094 §5)
kit/ pubblicato col pacchetto (ADR-0094 §5): il kit dell'agente (skills/, agents/, hooks/,
blocco-agents.md) e il template del boilerplate di `etl init` (boilerplate/)
api/ report di api-extractor dell'API pubblica (ADR-0093 §4)
scripts/ strumenti del repo (report dell'API pubblica, sorgente di ogni subpath)
tests/ test del framework e di integrazione; tests/package/ prova il dist/ costruito, tests/smoke/ il tarball installato
docs/ convenzioni, ADR, runbook, schede pipeline e sub-pipeline; docs/.vitepress/ è config e tema del sito, nel pacchetto
.claude/ settings, le copie noeva-etl-* del kit scritte da `etl agent sync` e gli strumenti
del solo core (skill etl-core, subagent project-pulse)
.github/ CI (quality gate) e template