Elido
8 min di letturaIngegneria

Rilasciata la migrazione da Dub.co: le cartelle diventano tag

Come abbiamo creato le importazioni con un clic da Dub.co per Elido: la API più pulita delle cinque, la conversione da cartelle a tag e perché questa migrazione è ideale per i team che hanno a cuore la residenza dei dati nell'UE.

Marius Voß
DevRel · edge infra
Diagramma della pipeline: API REST di Dub.co a sinistra che fluisce attraverso il worker di importazione di Elido nella tabella dei link, con un pannello laterale che elenca le garanzie numeriche (limite di 50k, budget di 30 minuti, 100 per pagina, cartelle convertite in tag)

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:

  1. Dub.co — bearer token, errori conformi a JSON-RFC, paginazione ?page= + ?limit=100, ogni campo documentato con payload di esempio.
  2. Short.io — pulita, booleano HasMore esplicito, ma il partizionamento per dominio necessita di lavoro sull'UX.
  3. Bitly — URL pagination.next conforme agli standard; la API reference di supporto è completa.
  4. TinyURL — Solo Pro/Bulk, il resto non è supportato; la documentazione è scarna.
  5. 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#

Prova Elido

Accorciatore di URL ospitato nell'UE: domini personalizzati, analisi approfondite e API aperta. Piano gratuito — senza carta di credito.

Tag
dub.co migration
url shortener
go worker
data migration
engineering
tier 3 integrations

Continua a leggere