Die fünfte und letzte Migrationsquelle in unserem Tier-3-Rollout wurde heute ausgeliefert. Fügen Sie einen Dub.co API-Token ein, filtern Sie optional nach Project-Slug, klicken Sie auf Start. Drei bis fünf Minuten später liegt jeder Link auf Ihrer Elido-Domain, wobei der Slug erhalten bleibt und die Dub-Ordnerstruktur in Elido-Tags abgeflacht wird.
Dieser Beitrag ist der Engineering-Bericht — was für Dub spezifisch ist, warum ihre API die sauberste der fünf von uns unterstützten Anbieter ist und was ein Dub-zu-Elido-Side-Grade motiviert.
Warum diese Migration existiert#
Dub.co ist das nächste Open-Source-Äquivalent zu Elido im Funktionsumfang. Starkes Produkt, saubere REST-API, modernes Dashboard. Der Migrationspfad hier ist für Teams gedacht, die sich aus einem von drei Gründen für Elido entscheiden:
- EU-Residenz. Elidos Data Plane ist in der EU verankert — Hetzner FRA + ASH POPs, OVH SGP für APAC, alle Click-Events landen standardmäßig in ClickHouse in der EU-Region. Dub Cloud ist in den USA verankert; die GDPR/Schrems-II-Position ist der Kompromiss.
- Edge-POP-Footprint. Drei regionale POPs mit p95 < 15ms Cache-HIT sind ein anderes Latenzziel als der reine Cloudflare-Workers-Pfad von Dub. Latenzsensitive Workloads (mobile-first, Ad-Attribution) spüren den Unterschied.
- Analytics-Tiefe. ClickHouse-basierte Click-Analytics mit pro-Event-Retention, Conversion-Forwarding zu GA4/Meta CAPI und vollständigem historischen Replay. Dubs Analytics ist sauber, aber PostgreSQL-aggregiert; die Grenze der Tiefe ist eine andere.
Wenn keiner dieser Punkte zutrifft, ist Dub ein gutes Produkt. Die Migration ist für die Teams da, auf die sie zutrifft.
Warum Dubs API die sauberste ist#
Wir haben jetzt Worker gegen fünf Vendor-APIs gebaut. Ranking nach Integrationsfreundlichkeit:
- Dub.co — Bearer-Token, JSON-RFC-konforme Fehler,
?page=+?limit=100Paginierung, jedes Feld dokumentiert mit Beispiel-Payloads. - Short.io — sauber,
HasMore-Boolean explizit, aber pro-Domain-Partitionierung benötigt UX-Arbeit. - Bitly —
pagination.nextURL ist standardkonform; die umgebende API-Referenz ist gründlich. - TinyURL — nur Pro/Bulk, der Rest ist nicht unterstützt; Dokumentation ist spärlich.
- Rebrandly —
?last=<id>Cursor ist okay, aber das 25-pro-Seite-Limit lässt alles langsam wirken.
Dubs Vorteil: Ihre Dokumentation enthält curl-Beispiele, ihre Fehlerantworten enthalten sowohl einen Maschinencode als auch eine menschenlesbare Nachricht, und ihre Paginierung ist die langweilige Art, bei der ?page=2&limit=100 genau so funktioniert, wie man es vermuten würde.
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 gibt kein HasMore-Flag zurück; wir leiten es von einer kurzen Seite ab. Dies ist das Standard-REST-Paginierungsmuster und es funktioniert einwandfrei — eine Seite, die kürzer ist als das Limit, bedeutet, dass wir fertig sind.
Ordner werden zu Tags abgeflacht#
Dub hat sowohl Ordner als auch Tags als Organisationsprimitive. Elido hat nur Tags. Also flacht die Migration Dub-Ordner in den Tag-Bag ab:
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 != "" {
// Dub-Ordner können verschachtelt sein; den vollständigen Pfad abflachen.
for _, segment := range strings.Split(link.Folder.Name, "/") {
seg := strings.TrimSpace(segment)
if seg != "" {
tags = append(tags, seg)
}
}
}
tags = append(tags, "imported:dub")
Ein Dub-Link im Ordner campaigns/q3-launch mit Tags paid und linkedin importiert mit den Tags paid, linkedin, campaigns, q3-launch und imported:dub. Die Filtersemantik in Elido handhabt dieselben Abrufmuster wie Dubs Ordner-UI — tag-equals, tag-contains, multi-tag-AND. Wir erfinden die Ordnerhierarchie nicht serverseitig neu; der Benutzer erhält eine flache Liste von Tags und die Filterprimitive.
Hätten wir Elido Ordner hinzufügen können? Ja. Wir entschieden uns für nur Tags, als Elidos Datenmodell in Phase 1 ausgeliefert wurde; Ordner sind sinnvoll für Desktop-Dateisystem-Mentalmodelle und weniger für Short-Link-Bulk-Operationen. Dub-Benutzer in Elido-Tags zu migrieren, ist die richtige Seite dieses Kompromisses.
Projektfilterung#
Dub verwendet "Workspaces" (in ihrer neueren UI) und nannte sie historisch "Projekte". Die API akzeptiert einen workspaceId-Parameter zum Filtern; der Launcher macht ihn als optionales Textfeld zugänglich. Fügen Sie den Workspace-Slug aus Ihrer Dub-URL ein oder lassen Sie ihn leer, um jeden Link zu greifen, den der Token sehen kann.
Dies spiegelt den Rebrandly-Workspace-Filter und das Short.io-Domainfeld wider. Drei unserer fünf Migrationsanbieter haben ein Pro-Account-Partitionierungskonzept; wir stellen es konsistent als optionale Texteingabe dar anstatt als befülltes Dropdown, da der typische Benutzer höchstens zwei Workspaces hat und der API-Listing-Endpunkt Latenz hinzufügt, die den Schliff nicht wert ist.
Was wir nicht migrieren#
Dubs Geo-Targeting- und Device-Targeting-Regeln. Sie sind ein mächtiges Dub-Feature, aber die Regelform lässt sich nicht 1:1 auf Elido Smart-Link-Regeln abbilden. Der Slug importiert; bauen Sie die Regeln mit Elidos Ausdruckssyntax neu auf, die permissiver ist, aber eine andere mentale Form hat.
Pro-Click-Historie. Universelles Limit über alle fünf Migrationsquellen hinweg. Dubs Pro-Click-Daten liegen hinter ihrem Analytics-Endpunkt, der an den Plantarif gebunden ist; neue Klicks landen ab dem Cutover in Elido-Analytics.
QR-Styling. Der Standard-Elido-QR wird neu generiert; benutzerdefinierte Designs müssen neu angewendet werden. Das imported:dub-Tag ist der Handle für die Bulk-Neuzuweisung.
Dub-Workspace-ACLs und Rollenkonfiguration. Gewähren Sie den Zugriff in Elido neu mittels SCIM/SSO oder Workspace-Mitgliedseinladungen; das Rollenmodell unterscheidet sich zwischen den beiden Produkten stark genug, dass ein automatisches Mapping als stille Privilegien-Eskalation erscheinen würde.
Selbstgehostetes Dub#
Dub ist Open-Source und selbstgehostete Dub-Instanzen sind üblich. Die Migration verwendet dieselbe REST-API, die das Dub-Cloud-Produkt offenlegt, daher bedeutet das Zeigen auf ein selbstgehostetes Dub, DUB_API_BASE zu überschreiben. Wir haben das in v1 nicht als Self-Serve-Einstellung freigegeben, da der operative Rattenschwanz nicht trivial ist — verschiedene Dub-Versionen legen subtil unterschiedliche Antwortformen offen, und wir wollen keinen Launcher ausliefern, der auf einem Dub v0.7-Deployment stillschweigend 500er-Fehler wirft, wenn v0.9 das getestete Ziel ist.
Für selbstgehostete Dub-Migrationen senden Sie eine E-Mail an [email protected] mit Ihrer Dub-Version, und wir führen eine einmalige Concierge-Migration durch. Sobald wir genug Versionen in freier Wildbahn gesehen haben, wird der Override zu einer Self-Serve-Dashboard-Einstellung.
Token-Behandlung#
Dieselbe One-Shot-Semantik wie bei den vier anderen Migrationsanbietern:
bgCtx := context.WithoutCancel(r.Context())
go h.dub.Run(bgCtx, job.ID, imports.DubJobOptions{
Token: req.Token,
WorkspaceID: req.WorkspaceID,
})
source_token_id bleibt NULL. Der Token lebt im api-core-Prozessspeicher für den Worker-Lauf und wird nach Abschluss verworfen. Keine Persistenz — dies ist eine One-Shot-Migration, kein wiederkehrender Vendor-Call.
context.WithoutCancel (Go 1.21+) hält den Worker über den HTTP-Request hinaus am Leben. Dasselbe Muster wie bei jedem anderen Migrationsanbieter in diesem Rollout.
Konfliktlösung und der Worker-Vertrag#
Identisch mit jedem anderen Anbieter. Suffix-Walks mylink-2, mylink-3, …, bis zu 50 Kandidaten; Skip lässt den bestehenden Elido-Link in Ruhe; Fail bricht beim ersten Konflikt ab. Worker-Vertrag — MaxLinksPerImport=50_000, ImportRunBudget=30*time.Minute — wird über alle fünf geteilt.
Der Lookup ist ein indizierter Read pro Zeile auf (domain_id, slug). Deterministische Suffix-Walks, freundlichere Fehler als das Fischen nach Uniqueness-Verletzungen in pgx.
Was wir mit Bitly verglichen haben#
Sowohl Dub als auch Bitly migrieren mit ungefähr demselben Durchsatz — 100 Links pro Seite, ~5 Inserts/Sek. anhaltend. Eine 5.000-Link-Quelle ist bei beiden Anbietern in 4–7 Minuten fertig. Der benutzer sichtbare Unterschied ist die Post-Import-Erfahrung: Dub-importierte Links kommen mit strukturierten Ordner-als-Tag-Breadcrumbs an; Bitly-importierte Links kommen nur mit dem imported:bitly-Tag und allen frei formatierten Bitly-Tags an.
Wiederaufnehmbarkeit und das Deploy-Problem#
Dasselbe Kompromiss wie bei den ersten vier Migrationen. Worker ist in-process; ein Mid-Import-Deploy tötet die Goroutine. Der 5-Minuten-Stuck-Sweep-Cron dreht jede running-Zeile ohne Fortschritt in 30 Minuten auf failed. Das erneute Ausführen ist idempotent unter Suffix- und Skip-Strategien.
Für Accounts über 10.000 Links würde sich die Wiederaufnehmbarkeit lohnen — wir würden den Dub-page-Cursor in import_jobs.source_filter aufzeichnen und ab der letzten abgeschlossenen Seite fortfahren. Alle fünf Migrationsanbieter teilen das gleiche In-Process-Design; wenn wir Wiederaufnehmbarkeit ausliefern, profitieren alle fünf.
Was kommt als nächstes für den Tier-3-Rollout#
Tier-3 ist fertig. Fünf Migrationsanbieter, eine geteilte import_jobs-Tabelle, ein geteilter Worker-Vertrag, eine geteilte Dashboard-Polling-UI, fünf SEO-Landings, fünf Engineering-Blogposts.
Was hinter Tier-3 in der Warteschlange steht:
- Wiederaufnehmbarkeit für Accounts nördlich von 10.000 Links. Vendor-spezifisches Cursor-Checkpointing.
- CSV-Export-Fallback für Benutzer auf Plänen mit widerrufenen Tokens. Derzeit nur Concierge.
- Tier-2 service_tokens Fundament — Vendor-Tokens zur wiederkehrenden Nutzung für Mailchimp, Brevo, Klaviyo. Der Migrationspfad validierte das JSONB-
source_filter-Muster; Tier-2 benötigt persistente verschlüsselte Tokens, was ADR-0036-Territorium ist.
Wenn Sie Elido von einem Dub-Workspace aus beobachtet haben, ist die Migrationsgeschichte jetzt dokumentiert. Probieren Sie es aus — Token bis zum letzten importierten Link in unter fünf Minuten bei typischen Accounts.
Verwandtes im Blog#
- Auslieferung der Bitly-Migration: ein Worker, ein Token, ein 30-Minuten-Budget
- Auslieferung der Rebrandly-Migration: 25-pro-Seite-Paginierung
- Auslieferung der Short.io-Migration: pro-Domain-Paginierung bei 150/Seite
- Auslieferung der TinyURL-Migration: Pro/Bulk-REST, kein Free-Tier-Pfad
- Short Links als Terraform: der Engineering-Eckpfeiler