Ruolo & ambito
Un'azienda e-commerce con un proprio ERP (NetSuite) spediva tramite uno strumento SaaS, con i costi e il controllo limitato sui contratti con i corrieri che ne derivano. CarrierAPI è il sostituto self-hosted: un'API che crea etichette, confronta tariffe, traccia le spedizioni ed elabora batch su più corrieri, con gli stessi punti di aggancio dello strumento precedente, così il passaggio da NetSuite ha potuto essere una sostituzione drop-in invece di una ricostruzione.
- Un'architettura ad adapter per corriere (PostNL, DHL Express e UPS come nucleo; DHL Parcel, FedEx, GLS e SendCloud stesso come adapter aggiuntivi), così aggiungere un nuovo corriere non richiede modifiche al resto del sistema.
- Sostituzione drop-in dello strumento SaaS precedente dentro NetSuite: stessi nomi dei campi personalizzati, modifiche minime all'integrazione SuiteScript esistente.
- Aggancio diretto ai record Item Fulfillment in NetSuite, più la sincronizzazione con Shopify e un'integrazione Amazon accanto ai corrieri.
- Due modi per gestire le credenziali dei corrieri: dall'interfaccia (su database, la via preferita) o tramite variabili d'ambiente (percorso legacy per i deployment esistenti).
Impatto
- Costi di spedizione e contratti con i corrieri tornati sotto controllo diretto, invece di dipendere da tariffe e condizioni di uno strato SaaS intermedio.
- Riparato il riconoscimento degli indirizzi per una classe di indirizzi prima interpretati male (l'estrazione del numero civico prendeva per errore l'ultimo numero invece del primo dopo il nome della via — sbagliato, per esempio, per gli indirizzi dei villaggi vacanze con numero civico e numero di chalet).
- La riconciliazione delle fatture UPS ha continuato a funzionare dopo che UPS ha cambiato due volte il formato di esportazione delle proprie fatture, basando il rilevamento delle colonne sul contenuto invece che su posizioni fisse, con verifica contro il totale che la fattura stessa dichiara.
- Chiusa una falla nelle sessioni per cui gli utenti eliminati mantenevano l'accesso fino a 24 ore, perché del token venivano controllate solo firma e scadenza — non se l'account esistesse ancora.
Architettura
Ogni corriere è un adapter dietro un'interfaccia condivisa (creazione e annullamento spedizioni, richiesta tariffe, tracking, servizi disponibili) — collegare un nuovo corriere non tocca il resto del sistema. Il backend è FastAPI (Python, async) con PostgreSQL come database primario e un worker in background basato su Redis (arq) per l'elaborazione in batch delle etichette, così creare centinaia di etichette insieme non blocca l'API. Le etichette sono archiviate in MinIO (compatibile S3), così lo storage non resta legato a un singolo cloud provider. Il frontend è una dashboard Next.js/React per gestire spedizioni, impostazioni dei corrieri e credenziali. Il tutto gira self-hosted con Docker Compose dietro Traefik, rilasciato con Coolify.
Scelta del modello
Nessuna AI/LLM: questo è deliberatamente un sistema deterministico — etichette, tariffe e tracking devono essere prevedibili e verificabili, non generati. La scelta chiave qui è stata self-hosted contro SaaS: uno strumento SaaS si attiva più in fretta, ma una piattaforma self-hosted dà controllo sui contratti con i corrieri, nessuna commissione per etichetta o per spedizione a uno strato intermedio, e la possibilità di costruire funzionalità (come l'integrazione diretta con NetSuite) esattamente su misura invece di aspettare ciò che un fornitore SaaS supporta o meno.
Costi & latenza
- Infrastruttura self-hosted (Docker Compose, PostgreSQL, Redis, MinIO) invece di un canone SaaS ricorrente per spedizione.
- La generazione delle etichette in batch è asincrona tramite una coda Redis (arq), così creare centinaia di etichette insieme mantiene l'API reattiva invece di lasciare in attesa chi ha fatto la richiesta.
- Riconciliazione delle fatture verificata su fatture UPS reali: tra le altre una fattura da 1.275 righe per 4.855,72 € e un export da 2.275 righe, entrambi elaborati correttamente dopo la correzione sul rilevamento delle colonne.
Lezioni apprese
Il parsing degli indirizzi olandesi sbagliava su una classe precisa di indirizzi (villaggi vacanze con numero civico e un numero di chalet separato, come «Hessenweg 83 41») perché il parser leggeva come civico l'ultimo numero della riga invece del primo dopo il nome della via. Risolto con un parser condiviso, verificato su un caso reale. L'import delle fatture UPS si è rotto due volte perché UPS ha cambiato il formato di esportazione (numero e ordine delle colonne spostati); l'approccio a posizioni fisse è stato sostituito da un rilevamento delle colonne basato sul contenuto, il cui risultato viene incrociato con il totale dichiarato dalla fattura stessa. Gli avvisi di validazione degli indirizzi inizialmente bloccavano del tutto la creazione di una spedizione; il comportamento è stato ridotto al blocco del solo acquisto automatico dell'etichetta, così una spedizione segnalata resta visibile e ritentabile invece di bloccarsi. E una vulnerabilità di sessione: gli utenti eliminati mantenevano l'accesso fino a 24 ore perché i token venivano controllati solo su firma e scadenza, non sull'esistenza dell'account — risolto verificando a ogni richiesta che l'account esista ancora.