La quinta e ultima sorgente di migrazione del nostro roll-out Tier-3 è stata rilasciata oggi. Incolla un Dub.co API token, filtra facoltativamente per slug di progetto e fai clic su Start. Dopo tre-cinque minuti, ogni link sarà sul tuo dominio Elido con lo slug preservato e la struttura delle cartelle di Dub convertita in tag di Elido.
Questo post è il resoconto ingegneristico: cosa c'è di specifico in Dub, perché la loro API è la più pulita tra i cinque vendor che supportiamo e cosa motiva una migrazione da Dub a Elido.
Perché esiste questa migrazione#
Dub.co è l'equivalente open-source più vicino a Elido per quanto riguarda le funzionalità. Ottimo prodotto, API REST pulita, dashboard moderna. Il percorso di migrazione qui è pensato per i team che scelgono Elido per uno di questi tre motivi:
- Residenza nell'UE. Il data plane di Elido è ancorato nell'UE — Hetzner FRA + ASH POP, OVH SGP per APAC; tutti gli eventi di clic finiscono per impostazione predefinita in ClickHouse nella regione UE. Dub Cloud è ancorato negli Stati Uniti; il posizionamento GDPR/Schrems-II è il compromesso.
- Footprint dei POP edge. Tre POP regionali con p95 < 15ms cache HIT rappresentano un target di latenza diverso rispetto al percorso basato esclusivamente su Cloudflare Workers di Dub. I carichi di lavoro sensibili alla latenza (mobile-first, ad-attribution) sentono la differenza.
- Profondità dell'analisi. Analisi dei clic basate su ClickHouse con conservazione per evento, inoltro delle conversioni a GA4/Meta CAPI e riproduzione storica completa. Le analisi di Dub sono pulite ma aggregate in PostgreSQL; il tetto di profondità è diverso.
Se nessuno di questi punti ti riguarda, Dub è un ottimo prodotto. La migrazione è qui per i team a cui invece interessa.
Perché l'API di Dub è la più pulita#
Abbiamo creato worker per le API di cinque vendor. Classifica per facilità di integrazione:
- Dub.co — bearer token, errori conformi a JSON-RFC, paginazione
?page=+?limit=100, ogni campo documentato con payload di esempio. - Short.io — pulita, booleano
HasMoreesplicito, ma il partizionamento per dominio necessita di lavoro sull'UX. - Bitly — URL
pagination.nextconforme agli standard; la API reference di supporto è completa. - TinyURL — Solo Pro/Bulk, il resto non è supportato; la documentazione è scarna.
- Rebrandly — il cursore
?last=<id>va bene ma il limite di 25 per pagina rende tutto lento.
Il punto di forza di Dub: la loro documentazione include esempi curl, le risposte agli errori includono sia un codice macchina che un messaggio umano, e la loro paginazione è quella classica in cui ?page=2&limit=100 funziona esattamente come immagineresti.
const dubPageSize = 100
page := 1
for {
resp, err := w.fetchPage(ctx, opts.Token, opts.WorkspaceID, page)
if err != nil { /* mark failed */ return }
if len(resp) == 0 { break }
for _, link := range resp { /* import */ }
if len(resp) < dubPageSize { break }
page++
}
Dub non restituisce un flag HasMore; lo deduciamo da una pagina corta. Questo è il pattern di paginazione REST standard e funziona bene — una pagina più corta del limite significa che abbiamo finito.
Le cartelle diventano tag#
Dub ha sia cartelle che tag come primitive di organizzazione. Elido ha solo i tag. Quindi la migrazione converte le cartelle di Dub nel set di tag:
tags := make([]string, 0, len(link.Tags)+2)
for _, t := range link.Tags {
tags = append(tags, t.Name)
}
if link.Folder != nil && link.Folder.Name != "" {
// Le cartelle di Dub possono essere nidificate; appiattiamo l'intero percorso.
for _, segment := range strings.Split(link.Folder.Name, "/") {
seg := strings.TrimSpace(segment)
if seg != "" {
tags = append(tags, seg)
}
}
}
tags = append(tags, "imported:dub")
Un link Dub nella cartella campaigns/q3-launch con tag paid e linkedin viene importato con i tag paid, linkedin, campaigns, q3-launch e imported:dub. La semantica dei filtri in Elido gestisce gli stessi pattern di recupero dell'interfaccia delle cartelle di Dub — tag-uguale, tag-contiene, AND multi-tag. Non stiamo reinventando la gerarchia delle cartelle lato server; l'utente ottiene un elenco piatto di tag e le primitive di filtro.
Avremmo potuto aggiungere le cartelle a Elido? Sì. Abbiamo scelto solo i tag quando il modello dati di Elido è stato rilasciato nella Fase 1; le cartelle hanno senso per i modelli mentali del file-system desktop e meno per le operazioni in blocco di link brevi. Migrare gli utenti Dub nei tag di Elido è la scelta giusta in questo compromesso.
Filtro dei progetti#
Dub utilizza "workspaces" (nella loro nuova UI) e storicamente li chiamava "projects". L'API accetta un parametro workspaceId per filtrare; il launcher lo espone come un campo di testo opzionale. Incolla lo slug del workspace dal tuo URL Dub, o lascialo vuoto per recuperare ogni link che il token può vedere.
Questo rispecchia il filtro workspace di Rebrandly e il campo dominio di Short.io. Tre dei nostri cinque vendor di migrazione hanno un concetto di partizionamento per account; lo esponiamo in modo coerente come input di testo opzionale piuttosto che come menu a tendina popolato, perché l'utente tipico ha al massimo due workspace e l' endpoint di elenco API aggiunge una latenza che non giustifica la rifinitura.
Cosa non migriamo#
Regole di geo-targeting e device-targeting di Dub. Sono una funzionalità potente di Dub, ma la forma della regola non è mappabile 1:1 alle regole smart-link di Elido. Lo slug viene importato; ricostruisci le regole usando la sintassi delle espressioni di Elido, che è più permissiva ma ha una forma mentale diversa.
Cronologia per clic. Limite universale su tutte e cinque le sorgenti di migrazione. I dati per clic di Dub risiedono dietro il loro endpoint di analisi, che è vincolato al piano; i nuovi clic finiscono nelle analisi di Elido a partire dal cutover.
Stile QR. Il QR predefinito di Elido viene rigenerato; i design personalizzati devono essere riapplicati. Il tag imported:dub è l'handle per la riassegnazione in blocco.
ACL del workspace e configurazione dei ruoli di Dub. Concedi nuovamente l'accesso in Elido usando SCIM/SSO o inviti ai membri del workspace; il modello di ruolo differisce abbastanza tra i due prodotti che una mappatura automatizzata emergerebbe come una escalation silenziosa dei privilegi.
Dub self-hosted#
Dub è open-source e le istanze Dub self-hosted sono comuni. La migrazione utilizza la stessa API REST che espone il prodotto Dub Cloud, quindi puntare a un Dub self-hosted significa sovrascrivere DUB_API_BASE. Non l'abbiamo esposto come impostazione self-serve nella v1 perché il carico operativo non è banale — versioni diverse di Dub espongono forme di risposta leggermente diverse, e non vogliamo rilasciare un launcher che vada silenziosamente in 500 su un deployment Dub v0.7 quando il target testato è la v0.9.
Per le migrazioni Dub self-hosted, invia un'email a [email protected] con la tua versione di Dub ed eseguiremo una migrazione assistita una tantum. Una volta viste abbastanza versioni in circolazione, l'override diventerà un'impostazione della dashboard self-serve.
Gestione dei token#
Stessa semantica "one-shot" degli altri quattro vendor di migrazione:
bgCtx := context.WithoutCancel(r.Context())
go h.dub.Run(bgCtx, job.ID, imports.DubJobOptions{
Token: req.Token,
WorkspaceID: req.WorkspaceID,
})
source_token_id rimane NULL. Il token vive nella memoria del processo api-core per l'esecuzione del worker, eliminato al completamento. Nessuna persistenza — questa è una migrazione "one-shot", non una chiamata ricorrente al vendor.
context.WithoutCancel (Go 1.21+) mantiene il worker attivo oltre la richiesta HTTP. Stesso pattern di ogni altro vendor di migrazione in questo roll-out.
Risoluzione dei conflitti e contratto del worker#
Identico a ogni altro vendor. Il suffisso esegue mylink-2, mylink-3, …, fino a 50 candidati; skip lascia intatto il link Elido esistente; fail interrompe al primo conflitto. Il contratto del worker — MaxLinksPerImport=50_000, ImportRunBudget=30*time.Minute — è condiviso tra tutti e cinque.
La ricerca è una lettura indicizzata per riga su (domain_id, slug). Suffissi deterministici, errori più amichevoli rispetto alla caccia alle violazioni di unicità in pgx.
Cosa abbiamo misurato rispetto a Bitly#
Sia Dub che Bitly migrano approssimativamente con lo stesso throughput — 100 link per pagina, ~5 inserimenti/sec sostenuti. Una sorgente da 5.000 link termina in 4–7 minuti per entrambi i vendor. La differenza visibile per l'utente è l'esperienza post-importazione: i link importati da Dub arrivano con breadcrumb strutturati cartella-come-tag; i link importati da Bitly arrivano solo con il tag imported:bitly ed eventuali tag Bitly a forma libera.
Resumability (Riprendibilità) e il problema del deploy#
Stesso compromesso delle prime quattro migrazioni. Il worker è in-process; un deploy a metà importazione uccide la goroutine. Il cron di "stuck-sweep" di 5 minuti trasforma qualsiasi riga running senza progressi in 30 minuti in failed. L'esecuzione è idempotente con strategie di suffisso e skip.
Per account con oltre 10.000 link, la riprendibilità sarebbe utile — registreremmo il cursore page di Dub in import_jobs.source_filter e riprenderemmo dall'ultima pagina completata. Tutti e cinque i vendor di migrazione condividono lo stesso design in-process; quando rilasceremo la riprendibilità, tutti e cinque ne beneficeranno.
Cosa c'è dopo per il roll-out Tier-3#
Il Tier-3 è terminato. Cinque vendor di migrazione, una tabella import_jobs condivisa, un contratto worker condiviso, una UI di polling della dashboard condivisa, cinque landing SEO, cinque post tecnici sul blog.
Cosa c'è in coda dopo il Tier-3:
- Resumability per account con oltre 10.000 link. Checkpoint del cursore per vendor.
- Fallback per esportazione CSV per utenti su piani con token revocati. Attualmente solo tramite assistenza dedicata.
- Fondazione service_tokens Tier-2 — token vendor a uso ricorrente per Mailchimp, Brevo, Klaviyo. Il percorso di migrazione ha validato il pattern JSONB
source_filter; il Tier-2 necessita di token crittografati persistenti, che è territorio di ADR-0036.
Se stavi osservando Elido da un workspace Dub, la storia della migrazione è ora documentata. Provalo — dal token all'ultimo link importato in meno di cinque minuti per gli account tipici.
Correlati sul blog#
- Shipping the Bitly migration: a worker, a token, a 30-minute budget
- Shipping the Rebrandly migration: 25-per-page pagination
- Shipping the Short.io migration: per-domain pagination at 150/page
- Shipping the TinyURL migration: Pro/Bulk REST, no free-tier path
- Short links as Terraform: the engineering cornerstone