From 0b44acdde1effac9aaab7c9a67e7463a8cfd82e0 Mon Sep 17 00:00:00 2001 From: Till JS Date: Mon, 18 May 2026 16:14:40 +0200 Subject: [PATCH] chore(mana): uload aus unified-App entfernen MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit uLoad ist nach Code/uload/ als eigenständiger Hono+Bun-Server migriert (siehe mana/docs/playbooks/ULOAD_GREENFIELD.md, υ-0..υ-7 durch). Live auf: - uload.mana.how → :3108 (SvelteKit-Web, Standalone) - uload-api.mana.how → :3107 (Hono-API, eigene Postgres-DB im `uload`-Schema) - ulo.ad → :3107 (Short-Redirect-Domain) Gelöscht / abgebaut: - Module: apps/mana/.../modules/uload + Routen + Locales - Top-Level: apps/uload/ (alter SvelteKit-Web + Hono-Server-Code) - docker-compose.macmini.yml uload-server Service-Block (alter Container :3070 wurde durch Standalone-Stack auf :3107 ersetzt) - mana-web env: PUBLIC_ULOAD_SERVER_URL / _CLIENT in compose + hooks.server.ts (env-Injection, window.__-Export, CSP-connectSrc), status/+page.server.ts Service-List - prometheus uload-server scrape job + mana.how/uload probe - shared-branding APP_BRANDING.uload + APP_ICONS.uload + MANA_APPS uload-Entry + UloadLogo - spiral-db MANA_APP_INDEX.uload (=21) - shared-types/spaces 5× 'uload' Modul-Einträge in den Space-Listen - Registries: app-registry/apps.ts (Uload registerApp + DownloadSimple icon + Header), categories, help-content, module-registry, splitscreen, hooks.server APP_SUBDOMAINS, data/tools/init - package.json dev:uload:* + deploy:landing:uload Scripts - i18n: uload in apps/{de,en,es,fr,it}.json Was BLEIBT: - cloudflared `uload.mana.how` → :3108, `uload-api.mana.how` → :3107, `ulo.ad` → :3107 — Standalone-Routes - docker-compose mana-auth CORS_ORIGINS uload.mana.how + ulo.ad — SSO für Standalone Dexie v67: - droppt links + uloadTags + uloadFolders + linkTags mana-web svelte-check 0/0 (7256 files), snapshot test 10/10. Co-Authored-By: Claude Opus 4.7 (1M context) --- apps/mana/apps/web/src/hooks.server.ts | 7 - .../apps/web/src/lib/app-registry/apps.ts | 14 +- .../web/src/lib/app-registry/help-content.ts | 11 - apps/mana/apps/web/src/lib/data/database.ts | 12 + .../web/src/lib/data/module-registry.test.ts | 3 - .../apps/web/src/lib/data/module-registry.ts | 2 - .../web/src/lib/i18n/locales/apps/de.json | 1 - .../web/src/lib/i18n/locales/apps/en.json | 1 - .../web/src/lib/i18n/locales/apps/es.json | 1 - .../web/src/lib/i18n/locales/apps/fr.json | 1 - .../web/src/lib/i18n/locales/apps/it.json | 1 - .../web/src/lib/i18n/locales/uload/de.json | 286 ------- .../web/src/lib/i18n/locales/uload/en.json | 286 ------- .../web/src/lib/i18n/locales/uload/es.json | 286 ------- .../web/src/lib/i18n/locales/uload/fr.json | 286 ------- .../web/src/lib/i18n/locales/uload/it.json | 286 ------- .../web/src/lib/modules/uload/ListView.svelte | 242 ------ .../web/src/lib/modules/uload/collections.ts | 113 --- .../apps/web/src/lib/modules/uload/index.ts | 33 - .../src/lib/modules/uload/module.config.ts | 11 - .../apps/web/src/lib/modules/uload/queries.ts | 273 ------ .../apps/web/src/lib/modules/uload/types.ts | 46 - .../lib/modules/uload/views/DetailView.svelte | 178 ---- .../apps/web/src/lib/splitscreen/registry.ts | 1 - .../web/src/routes/(app)/uload/+page.svelte | 804 ------------------ .../(app)/uload/analytics/[id]/+page.svelte | 393 --------- .../src/routes/(app)/uload/links/+page.svelte | 353 -------- .../routes/(app)/uload/settings/+page.svelte | 206 ----- .../src/routes/(app)/uload/tags/+page.svelte | 182 ---- .../web/src/routes/status/+page.server.ts | 1 - apps/uload/CLAUDE.md | 128 --- apps/uload/README.md | 151 ---- apps/uload/apps/landing/astro.config.mjs | 16 - apps/uload/apps/landing/package.json | 25 - .../apps/landing/src/components/Footer.astro | 114 --- .../landing/src/components/HeroSection.astro | 195 ----- .../landing/src/components/Navigation.astro | 86 -- .../src/content/blog/link-tracking-guide.md | 92 -- .../content/blog/psychologie-kurzer-urls.md | 76 -- apps/uload/apps/landing/src/content/config.ts | 17 - apps/uload/apps/landing/src/env.d.ts | 2 - .../apps/landing/src/layouts/BaseLayout.astro | 59 -- .../landing/src/layouts/LegalLayout.astro | 28 - apps/uload/apps/landing/src/pages/about.astro | 130 --- apps/uload/apps/landing/src/pages/agb.astro | 76 -- .../apps/landing/src/pages/blog/[slug].astro | 95 --- .../apps/landing/src/pages/blog/index.astro | 69 -- .../apps/landing/src/pages/datenschutz.astro | 91 -- .../apps/landing/src/pages/features.astro | 169 ---- .../apps/landing/src/pages/impressum.astro | 63 -- apps/uload/apps/landing/src/pages/index.astro | 235 ----- .../apps/landing/src/pages/sicherheit.astro | 202 ----- apps/uload/apps/landing/src/styles/global.css | 92 -- apps/uload/apps/landing/tailwind.config.mjs | 48 -- apps/uload/apps/landing/tsconfig.json | 11 - apps/uload/apps/server/Dockerfile | 16 - apps/uload/apps/server/package.json | 22 - apps/uload/apps/server/src/config.ts | 30 - apps/uload/apps/server/src/db/connection.ts | 14 - apps/uload/apps/server/src/index.ts | 51 -- .../uload/apps/server/src/routes/analytics.ts | 33 - apps/uload/apps/server/src/routes/email.ts | 9 - apps/uload/apps/server/src/routes/health.ts | 10 - apps/uload/apps/server/src/routes/public.ts | 44 - apps/uload/apps/server/src/routes/redirect.ts | 74 -- apps/uload/apps/server/src/routes/stripe.ts | 73 -- .../apps/server/src/services/analytics.ts | 72 -- .../apps/server/src/services/redirect.ts | 76 -- apps/uload/apps/server/tsconfig.json | 16 - apps/uload/package.json | 5 - .../packages/uload-database/package.json | 23 - .../packages/uload-database/src/index.ts | 3 - .../packages/uload-database/src/schema.ts | 42 - .../packages/uload-database/tsconfig.json | 14 - docker-compose.macmini.yml | 30 - docker/prometheus/prometheus.yml | 8 - package.json | 6 - packages/shared-branding/src/app-icons.ts | 3 - packages/shared-branding/src/config.ts | 13 - packages/shared-branding/src/index.ts | 1 - .../src/logos/UloadLogo.svelte | 13 - packages/shared-branding/src/logos/index.ts | 1 - packages/shared-branding/src/mana-apps.ts | 17 - packages/shared-types/src/spaces.ts | 5 - packages/spiral-db/src/schema.ts | 1 - 85 files changed, 13 insertions(+), 7302 deletions(-) delete mode 100644 apps/mana/apps/web/src/lib/i18n/locales/uload/de.json delete mode 100644 apps/mana/apps/web/src/lib/i18n/locales/uload/en.json delete mode 100644 apps/mana/apps/web/src/lib/i18n/locales/uload/es.json delete mode 100644 apps/mana/apps/web/src/lib/i18n/locales/uload/fr.json delete mode 100644 apps/mana/apps/web/src/lib/i18n/locales/uload/it.json delete mode 100644 apps/mana/apps/web/src/lib/modules/uload/ListView.svelte delete mode 100644 apps/mana/apps/web/src/lib/modules/uload/collections.ts delete mode 100644 apps/mana/apps/web/src/lib/modules/uload/index.ts delete mode 100644 apps/mana/apps/web/src/lib/modules/uload/module.config.ts delete mode 100644 apps/mana/apps/web/src/lib/modules/uload/queries.ts delete mode 100644 apps/mana/apps/web/src/lib/modules/uload/types.ts delete mode 100644 apps/mana/apps/web/src/lib/modules/uload/views/DetailView.svelte delete mode 100644 apps/mana/apps/web/src/routes/(app)/uload/+page.svelte delete mode 100644 apps/mana/apps/web/src/routes/(app)/uload/analytics/[id]/+page.svelte delete mode 100644 apps/mana/apps/web/src/routes/(app)/uload/links/+page.svelte delete mode 100644 apps/mana/apps/web/src/routes/(app)/uload/settings/+page.svelte delete mode 100644 apps/mana/apps/web/src/routes/(app)/uload/tags/+page.svelte delete mode 100644 apps/uload/CLAUDE.md delete mode 100644 apps/uload/README.md delete mode 100644 apps/uload/apps/landing/astro.config.mjs delete mode 100644 apps/uload/apps/landing/package.json delete mode 100644 apps/uload/apps/landing/src/components/Footer.astro delete mode 100644 apps/uload/apps/landing/src/components/HeroSection.astro delete mode 100644 apps/uload/apps/landing/src/components/Navigation.astro delete mode 100644 apps/uload/apps/landing/src/content/blog/link-tracking-guide.md delete mode 100644 apps/uload/apps/landing/src/content/blog/psychologie-kurzer-urls.md delete mode 100644 apps/uload/apps/landing/src/content/config.ts delete mode 100644 apps/uload/apps/landing/src/env.d.ts delete mode 100644 apps/uload/apps/landing/src/layouts/BaseLayout.astro delete mode 100644 apps/uload/apps/landing/src/layouts/LegalLayout.astro delete mode 100644 apps/uload/apps/landing/src/pages/about.astro delete mode 100644 apps/uload/apps/landing/src/pages/agb.astro delete mode 100644 apps/uload/apps/landing/src/pages/blog/[slug].astro delete mode 100644 apps/uload/apps/landing/src/pages/blog/index.astro delete mode 100644 apps/uload/apps/landing/src/pages/datenschutz.astro delete mode 100644 apps/uload/apps/landing/src/pages/features.astro delete mode 100644 apps/uload/apps/landing/src/pages/impressum.astro delete mode 100644 apps/uload/apps/landing/src/pages/index.astro delete mode 100644 apps/uload/apps/landing/src/pages/sicherheit.astro delete mode 100644 apps/uload/apps/landing/src/styles/global.css delete mode 100644 apps/uload/apps/landing/tailwind.config.mjs delete mode 100644 apps/uload/apps/landing/tsconfig.json delete mode 100644 apps/uload/apps/server/Dockerfile delete mode 100644 apps/uload/apps/server/package.json delete mode 100644 apps/uload/apps/server/src/config.ts delete mode 100644 apps/uload/apps/server/src/db/connection.ts delete mode 100644 apps/uload/apps/server/src/index.ts delete mode 100644 apps/uload/apps/server/src/routes/analytics.ts delete mode 100644 apps/uload/apps/server/src/routes/email.ts delete mode 100644 apps/uload/apps/server/src/routes/health.ts delete mode 100644 apps/uload/apps/server/src/routes/public.ts delete mode 100644 apps/uload/apps/server/src/routes/redirect.ts delete mode 100644 apps/uload/apps/server/src/routes/stripe.ts delete mode 100644 apps/uload/apps/server/src/services/analytics.ts delete mode 100644 apps/uload/apps/server/src/services/redirect.ts delete mode 100644 apps/uload/apps/server/tsconfig.json delete mode 100644 apps/uload/package.json delete mode 100644 apps/uload/packages/uload-database/package.json delete mode 100644 apps/uload/packages/uload-database/src/index.ts delete mode 100644 apps/uload/packages/uload-database/src/schema.ts delete mode 100644 apps/uload/packages/uload-database/tsconfig.json delete mode 100644 packages/shared-branding/src/logos/UloadLogo.svelte diff --git a/apps/mana/apps/web/src/hooks.server.ts b/apps/mana/apps/web/src/hooks.server.ts index 00ac5d8df..0bb6796cf 100644 --- a/apps/mana/apps/web/src/hooks.server.ts +++ b/apps/mana/apps/web/src/hooks.server.ts @@ -15,8 +15,6 @@ import { setSecurityHeaders } from '@mana/shared-utils/security-headers'; * - Media → mana-media (CAS / thumbnails) * - LLM → mana-llm (server-side LLM proxy) * - Events → mana-events (public RSVP flow) - * - Uload server → standalone short-link redirect/click tracking - * - Memoro server → standalone voice memo processing * - Glitchtip DSN → client-side error reporting * * Per-app HTTP backends (todo-api, calendar-api, contacts-api, chat-api, @@ -33,8 +31,6 @@ const PUBLIC_GLITCHTIP_DSN = process.env.PUBLIC_GLITCHTIP_DSN || ''; const PUBLIC_SYNC_SERVER_URL_CLIENT = process.env.PUBLIC_SYNC_SERVER_URL_CLIENT || process.env.PUBLIC_SYNC_SERVER_URL || ''; -const PUBLIC_ULOAD_SERVER_URL_CLIENT = - process.env.PUBLIC_ULOAD_SERVER_URL_CLIENT || process.env.PUBLIC_ULOAD_SERVER_URL || ''; const PUBLIC_MANA_MEDIA_URL_CLIENT = process.env.PUBLIC_MANA_MEDIA_URL_CLIENT || process.env.PUBLIC_MANA_MEDIA_URL || ''; const PUBLIC_MANA_LLM_URL_CLIENT = @@ -153,7 +149,6 @@ const APP_SUBDOMAINS = new Set([ 'calc', 'inventory', 'times', - 'uload', 'questions', ]); @@ -222,7 +217,6 @@ export const handle: Handle = async ({ event, resolve }) => { window.__PUBLIC_MANA_AUTH_URL__ = ${JSON.stringify(PUBLIC_MANA_AUTH_URL_CLIENT)}; window.__PUBLIC_AUTH_WEB_URL__ = ${JSON.stringify(PUBLIC_AUTH_WEB_URL_CLIENT)}; window.__PUBLIC_SYNC_SERVER_URL__ = ${JSON.stringify(PUBLIC_SYNC_SERVER_URL_CLIENT)}; -window.__PUBLIC_ULOAD_SERVER_URL__ = ${JSON.stringify(PUBLIC_ULOAD_SERVER_URL_CLIENT)}; window.__PUBLIC_MANA_MEDIA_URL__ = ${JSON.stringify(PUBLIC_MANA_MEDIA_URL_CLIENT)}; window.__PUBLIC_MANA_LLM_URL__ = ${JSON.stringify(PUBLIC_MANA_LLM_URL_CLIENT)}; window.__PUBLIC_MANA_EVENTS_URL__ = ${JSON.stringify(PUBLIC_MANA_EVENTS_URL_CLIENT)}; @@ -257,7 +251,6 @@ window.__PUBLIC_GLITCHTIP_DSN__ = ${JSON.stringify(PUBLIC_GLITCHTIP_DSN)}; connectSrc: [ PUBLIC_MANA_AUTH_URL_CLIENT, PUBLIC_SYNC_SERVER_URL_CLIENT, - PUBLIC_ULOAD_SERVER_URL_CLIENT, PUBLIC_MANA_MEDIA_URL_CLIENT, PUBLIC_MANA_LLM_URL_CLIENT, PUBLIC_MANA_EVENTS_URL_CLIENT, diff --git a/apps/mana/apps/web/src/lib/app-registry/apps.ts b/apps/mana/apps/web/src/lib/app-registry/apps.ts index 10690f0ea..bacc1482c 100644 --- a/apps/mana/apps/web/src/lib/app-registry/apps.ts +++ b/apps/mana/apps/web/src/lib/app-registry/apps.ts @@ -32,7 +32,6 @@ import { Binoculars, ArrowsInCardinal, Buildings, - DownloadSimple, Calculator, Lightning, PencilRuler, @@ -100,7 +99,7 @@ import { // dreams · firsts · lasts · habits · recipes // Places & ev.: places · events // Creative: picture · music · photos -// Tools: uload · calc · inventory · +// Tools: calc · inventory · // storage · skilltree · questions // Long-tail: quotes · automations · companion · wetter · // goals · website · spaces · augur · @@ -678,17 +677,6 @@ registerApp({ }, }); -registerApp({ - id: 'uload', - name: 'uLoad', - color: '#0EA5E9', - icon: DownloadSimple, - views: { - list: { load: () => import('$lib/modules/uload/ListView.svelte') }, - detail: { load: () => import('$lib/modules/uload/views/DetailView.svelte') }, - }, -}); - registerApp({ id: 'calc', name: 'Calc', diff --git a/apps/mana/apps/web/src/lib/app-registry/help-content.ts b/apps/mana/apps/web/src/lib/app-registry/help-content.ts index 8f90b895f..1f7207188 100644 --- a/apps/mana/apps/web/src/lib/app-registry/help-content.ts +++ b/apps/mana/apps/web/src/lib/app-registry/help-content.ts @@ -315,17 +315,6 @@ export const MODULE_HELP: Record = { ], tips: ['Definiere Kategorien nach Lebensbereichen für eine gute Übersicht'], }, - uload: { - description: - 'Quick-Upload — Dateien schnell hochladen und teilbare Links erstellen. Ideal zum schnellen Teilen.', - features: [ - 'Drag & Drop Upload', - 'Teilbare Download-Links generieren', - 'Verschiedene Dateitypen unterstützt', - 'Gespeichert auf deinem eigenen Server', - ], - tips: ['Nutze uload für schnelles Teilen — drag die Datei rein, Link kopieren, fertig'], - }, calc: { description: 'Taschenrechner mit Berechnungsverlauf. Ergebnisse bleiben gespeichert und sind jederzeit abrufbar.', diff --git a/apps/mana/apps/web/src/lib/data/database.ts b/apps/mana/apps/web/src/lib/data/database.ts index 045a0624c..6ae9c9e9c 100644 --- a/apps/mana/apps/web/src/lib/data/database.ts +++ b/apps/mana/apps/web/src/lib/data/database.ts @@ -1614,6 +1614,18 @@ db.version(66) }); }); +// v67 — uLoad module retirement (2026-05-18). +// uLoad ist nach Code/uload/ als eigenständiger Hono+Bun-Server +// auf uload.mana.how + uload-api.mana.how migriert (eigene Postgres- +// DB im `uload`-Schema, JWKS-Auth). Tabellen werden hier komplett +// gedroppt. +db.version(67).stores({ + links: null, + uloadTags: null, + uloadFolders: null, + linkTags: null, +}); + // ─── Sync Routing ────────────────────────────────────────── // SYNC_APP_MAP, TABLE_TO_SYNC_NAME, TABLE_TO_APP, SYNC_NAME_TO_TABLE, // toSyncName() and fromSyncName() are now derived from per-module diff --git a/apps/mana/apps/web/src/lib/data/module-registry.test.ts b/apps/mana/apps/web/src/lib/data/module-registry.test.ts index 0204fa380..2ebe87872 100644 --- a/apps/mana/apps/web/src/lib/data/module-registry.test.ts +++ b/apps/mana/apps/web/src/lib/data/module-registry.test.ts @@ -218,7 +218,6 @@ describe('module-registry — snapshot', () => { 'entryTags', ], questions: ['qCollections', 'questions', 'answers', 'questionTags'], - uload: ['links', 'uloadTags', 'uloadFolders', 'linkTags'], calc: ['calculations', 'savedFormulas'], guides: ['guides', 'sections', 'steps', 'guideCollections', 'runs', 'guideTags'], habits: ['habits', 'habitLogs'], @@ -303,8 +302,6 @@ describe('module-registry — snapshot', () => { timeCountdownTimers: 'countdownTimers', timeWorldClocks: 'worldClocks', qCollections: 'collections', - uloadTags: 'tags', - uloadFolders: 'folders', guideCollections: 'collections', socialEvents: 'events', financeCategories: 'categories', diff --git a/apps/mana/apps/web/src/lib/data/module-registry.ts b/apps/mana/apps/web/src/lib/data/module-registry.ts index ac073f03f..a238419bd 100644 --- a/apps/mana/apps/web/src/lib/data/module-registry.ts +++ b/apps/mana/apps/web/src/lib/data/module-registry.ts @@ -65,7 +65,6 @@ import { photosModuleConfig } from '$lib/modules/photos/module.config'; import { skilltreeModuleConfig } from '$lib/modules/skilltree/module.config'; import { timesModuleConfig } from '$lib/modules/times/module.config'; import { questionsModuleConfig } from '$lib/modules/questions/module.config'; -import { uloadModuleConfig } from '$lib/modules/uload/module.config'; import { calcModuleConfig } from '$lib/modules/calc/module.config'; import { guidesModuleConfig } from '$lib/modules/guides/module.config'; import { habitsModuleConfig } from '$lib/modules/habits/module.config'; @@ -119,7 +118,6 @@ export const MODULE_CONFIGS: readonly ModuleConfig[] = [ skilltreeModuleConfig, timesModuleConfig, questionsModuleConfig, - uloadModuleConfig, calcModuleConfig, guidesModuleConfig, habitsModuleConfig, diff --git a/apps/mana/apps/web/src/lib/i18n/locales/apps/de.json b/apps/mana/apps/web/src/lib/i18n/locales/apps/de.json index 922723f15..3d5c8a389 100644 --- a/apps/mana/apps/web/src/lib/i18n/locales/apps/de.json +++ b/apps/mana/apps/web/src/lib/i18n/locales/apps/de.json @@ -19,7 +19,6 @@ "inventory": "Inventar", "questions": "Recherche", "skilltree": "Skills", - "uload": "uLoad", "calc": "Rechner", "period": "Periode", "body": "Körper", diff --git a/apps/mana/apps/web/src/lib/i18n/locales/apps/en.json b/apps/mana/apps/web/src/lib/i18n/locales/apps/en.json index 8e3dfe909..309c2f9ef 100644 --- a/apps/mana/apps/web/src/lib/i18n/locales/apps/en.json +++ b/apps/mana/apps/web/src/lib/i18n/locales/apps/en.json @@ -19,7 +19,6 @@ "inventory": "Inventory", "questions": "Research", "skilltree": "Skills", - "uload": "uLoad", "calc": "Calculator", "period": "Period", "body": "Body", diff --git a/apps/mana/apps/web/src/lib/i18n/locales/apps/es.json b/apps/mana/apps/web/src/lib/i18n/locales/apps/es.json index 6090b4419..b5ce0b2db 100644 --- a/apps/mana/apps/web/src/lib/i18n/locales/apps/es.json +++ b/apps/mana/apps/web/src/lib/i18n/locales/apps/es.json @@ -19,7 +19,6 @@ "inventory": "Inventario", "questions": "Investigación", "skilltree": "Skills", - "uload": "uLoad", "calc": "Calculadora", "period": "Ciclo", "body": "Cuerpo", diff --git a/apps/mana/apps/web/src/lib/i18n/locales/apps/fr.json b/apps/mana/apps/web/src/lib/i18n/locales/apps/fr.json index ea75a3d1c..c112e9859 100644 --- a/apps/mana/apps/web/src/lib/i18n/locales/apps/fr.json +++ b/apps/mana/apps/web/src/lib/i18n/locales/apps/fr.json @@ -19,7 +19,6 @@ "inventory": "Inventaire", "questions": "Recherche", "skilltree": "Skills", - "uload": "uLoad", "calc": "Calculatrice", "period": "Règles", "body": "Corps", diff --git a/apps/mana/apps/web/src/lib/i18n/locales/apps/it.json b/apps/mana/apps/web/src/lib/i18n/locales/apps/it.json index a6f4e941f..0d9dbc1f6 100644 --- a/apps/mana/apps/web/src/lib/i18n/locales/apps/it.json +++ b/apps/mana/apps/web/src/lib/i18n/locales/apps/it.json @@ -19,7 +19,6 @@ "inventory": "Inventario", "questions": "Ricerca", "skilltree": "Skills", - "uload": "uLoad", "calc": "Calcolatrice", "period": "Ciclo", "body": "Corpo", diff --git a/apps/mana/apps/web/src/lib/i18n/locales/uload/de.json b/apps/mana/apps/web/src/lib/i18n/locales/uload/de.json deleted file mode 100644 index 254f2713f..000000000 --- a/apps/mana/apps/web/src/lib/i18n/locales/uload/de.json +++ /dev/null @@ -1,286 +0,0 @@ -{ - "nav": { - "links": "Links", - "tags": "Tags", - "analytics": "Analytics", - "settings": "Einstellungen" - }, - "links": { - "title": "Links", - "newLink": "Neuer Link", - "hide": "Ausblenden", - "url": "URL", - "urlPlaceholder": "https://example.com/long-url-here", - "titleLabel": "Titel (optional)", - "titlePlaceholder": "Mein Link", - "customCode": "Custom Code (optional)", - "customCodePlaceholder": "mein-link", - "utmParams": "UTM-Parameter", - "create": "Link erstellen", - "search": "Links durchsuchen...", - "all": "Alle", - "active": "Aktiv", - "inactive": "Inaktiv", - "allFolders": "Alle Ordner", - "noLinks": "Noch keine Links", - "noLinksDesc": "Erstelle deinen ersten gekürzten Link!", - "copied": "Link kopiert!", - "created": "Link erstellt", - "updated": "Link aktualisiert", - "deleted": "Link gelöscht", - "edit": "Bearbeiten", - "editTitle": "Link bearbeiten", - "save": "Speichern", - "cancel": "Abbrechen", - "delete": "Löschen", - "deleteConfirm": "wirklich löschen?", - "activate": "Aktivieren", - "deactivate": "Deaktivieren", - "copyLink": "Link kopieren", - "qrCode": "QR-Code", - "qrDownload": "QR herunterladen", - "clicks": "clicks" - }, - "tags": { - "title": "Tags", - "newTag": "Neuer Tag", - "name": "Name", - "namePlaceholder": "z.B. Social Media", - "color": "Farbe", - "create": "Erstellen", - "noTags": "Noch keine Tags", - "noTagsDesc": "Erstelle Tags um deine Links zu organisieren.", - "created": "Tag erstellt", - "updated": "Tag aktualisiert", - "deleted": "Tag gelöscht", - "linksCount": "Links" - }, - "analytics": { - "title": "Analytics", - "clicks": "Clicks", - "unique": "Unique", - "status": "Status", - "created": "Erstellt", - "clicksOverTime": "Clicks über Zeit", - "devices": "Geräte", - "referrers": "Referrer", - "countries": "Länder", - "noData": "Keine Daten", - "noDataPeriod": "Noch keine Daten für diesen Zeitraum", - "authRequired": "Analytics nur für angemeldete Nutzer", - "localClicks": "Lokale Click-Counts", - "unknown": "Unbekannt", - "direct": "Direkt" - }, - "settings": { - "title": "Einstellungen", - "account": "Account", - "email": "E-Mail", - "name": "Name", - "data": "Daten", - "clearData": "Lokale Daten löschen", - "clearConfirm": "Alle lokalen Daten löschen? Dies kann nicht rückgängig gemacht werden.", - "cleared": "Lokale Daten gelöscht", - "logout": "Abmelden", - "guestHint": "Du bist als Gast unterwegs.", - "loginToSync": "Anmelden um Daten zu synchronisieren." - }, - "common": { - "back": "Zurück", - "login": "Anmelden", - "source": "Source", - "medium": "Medium", - "campaign": "Campaign" - }, - "list_view": { - "empty_title": "Keine Links", - "add_placeholder": "URL einfügen...", - "err_invalid_url": "Ungültige URL", - "header_links": "{count} Links", - "header_clicks": "{count} Klicks", - "header_folders": "{count} Ordner", - "add_button": "Neuer Link" - }, - "detail_view": { - "not_found": "Link nicht gefunden", - "confirm_delete": "Link wirklich löschen?", - "deleted_toast": "Link gelöscht", - "placeholder_title": "Titel...", - "label_url": "URL", - "label_short_code": "Kurzcode", - "label_short_code_legacy": "Short Code", - "placeholder_short_code": "custom-code", - "label_active": "Aktiv", - "yes": "Ja", - "no": "Nein", - "label_clicks": "Klicks", - "label_expires_at": "Ablaufdatum", - "section_description": "Beschreibung", - "placeholder_description": "Beschreibung hinzufügen...", - "meta_created": "Erstellt: {date}", - "meta_updated": "Bearbeitet: {date}" - }, - "page": { - "title": "uLoad - Mana", - "all_links": "Alle Links", - "counts": "{links} Links · {folders} Ordner", - "counts_no_folders": "{links} Links", - "hide_form": "- Ausblenden", - "show_form": "+ Neuer Link", - "err_invalid_url_input": "Bitte eine gültige URL eingeben (mit https://)", - "err_invalid_custom_code": "Custom Code darf nur Buchstaben, Zahlen, - und _ enthalten", - "err_short_code_taken": "Short Code \"{code}\" ist bereits vergeben", - "err_max_clicks": "Max Klicks muss mindestens 1 sein", - "err_expires_past": "Ablaufdatum muss in der Zukunft liegen", - "toast_created": "Link erstellt: {code}", - "toast_updated": "Link aktualisiert", - "confirm_delete": "\"{name}\" wirklich löschen?", - "toast_deleted": "Link gelöscht", - "toast_copied": "Link kopiert!", - "label_title": "Titel (optional)", - "placeholder_title": "Mein Link", - "label_custom_code": "Custom Code (optional)", - "placeholder_custom_code": "mein-link", - "section_advanced": "Erweitert", - "label_expires": "Ablaufdatum", - "label_password": "Passwort", - "placeholder_optional": "Optional", - "label_max_clicks": "Max Klicks", - "placeholder_unlimited": "Unbegrenzt", - "section_utm": "UTM-Parameter", - "label_source": "Source", - "placeholder_source": "newsletter", - "label_medium": "Medium", - "placeholder_medium": "email", - "label_campaign": "Campaign", - "placeholder_campaign": "spring-2026", - "action_create": "Link erstellen", - "placeholder_search": "Links durchsuchen...", - "option_all": "Alle", - "option_active": "Aktiv", - "option_inactive": "Inaktiv", - "option_all_folders": "Alle Ordner", - "empty_title": "Noch keine Links", - "empty_desc": "Erstelle deinen ersten gekürzten Link!", - "badge_utm": "UTM", - "badge_password": "Passwort", - "badge_expires": "Ablauf", - "badge_expires_title": "Läuft ab: {date}", - "action_analytics_title": "Analytics", - "action_copy_title": "Link kopieren", - "action_qr_title": "QR-Code", - "action_edit_title": "Bearbeiten", - "action_activate_title": "Aktivieren", - "action_deactivate_title": "Deaktivieren", - "action_delete_title": "Löschen", - "modal_edit_title": "Link bearbeiten", - "label_url_modal": "URL", - "label_title_modal": "Titel", - "label_short_code_modal": "Short Code", - "short_code_locked": "(nicht änderbar)", - "action_cancel": "Abbrechen", - "action_save": "Speichern", - "modal_qr_title": "QR-Code", - "qr_alt": "QR Code für {code}", - "action_copy_link": "Link kopieren", - "action_download_qr": "QR herunterladen" - }, - "links_route": { - "title": "Alle Links - uLoad - Mana", - "heading": "Alle Links", - "action_back_title": "Zurück", - "action_select_done": "Fertig", - "action_select_start": "Auswählen", - "placeholder_search": "Links durchsuchen...", - "option_all": "Alle", - "option_active": "Aktiv", - "option_inactive": "Inaktiv", - "option_all_folders": "Alle Ordner", - "selected_count": "{count} ausgewählt", - "action_bulk_toggle": "Aktivieren/Deaktivieren", - "action_bulk_delete": "Löschen", - "confirm_bulk_delete": "{count} Link(s) löschen?", - "toast_bulk_deleted": "{count} Links gelöscht", - "toast_bulk_updated": "{count} Links aktualisiert", - "empty_title": "Keine Links gefunden", - "empty_filtered": "Versuche andere Filtereinstellungen.", - "empty_root": "Erstelle Links auf der uLoad-Hauptseite.", - "action_copy_title": "Link kopieren", - "action_activate_title": "Aktivieren", - "action_deactivate_title": "Deaktivieren", - "action_delete_title": "Löschen", - "action_analytics_title": "Analytics", - "toast_copied": "Link kopiert!", - "confirm_delete_single": "\"{name}\" wirklich löschen?", - "toast_deleted_single": "Link gelöscht" - }, - "analytics_route": { - "title": "Analytics - uLoad - Mana", - "page_title": "Link", - "action_back_title": "Zurück", - "heading": "Analytics", - "not_found": "Link nicht gefunden", - "stat_clicks": "Clicks", - "stat_unique": "Unique", - "stat_status": "Status", - "status_active": "Aktiv", - "status_inactive": "Inaktiv", - "stat_created": "Erstellt", - "section_details": "Link Details", - "label_target_url": "Ziel-URL", - "label_title": "Titel", - "label_utm_params": "UTM-Parameter", - "utm_source": "Source:", - "utm_medium": "Medium:", - "utm_campaign": "Campaign:", - "label_expires_at": "Läuft ab", - "label_max_clicks": "Max Klicks", - "max_clicks_value": "{used} / {max}", - "label_password_protected": "Passwortgeschützt", - "yes": "Ja", - "section_timeline": "Clicks über Zeit", - "days_unit": "{days}T", - "hint_no_server": "Detaillierte Analytics sind verfügbar, wenn der uLoad-Server verbunden ist.", - "hint_local_count": "Lokaler Click-Count: {count}", - "empty_period": "Noch keine Daten für diesen Zeitraum", - "section_devices": "Geräte", - "unknown": "Unbekannt", - "empty_no_data": "Keine Daten", - "section_referrers": "Referrer", - "direct": "Direkt", - "section_countries": "Länder" - }, - "settings_route": { - "title": "uLoad-Einstellungen — Mana", - "heading": "uLoad-Einstellungen", - "subtitle": "Datenübersicht · Export · Gefahrenzone", - "section_data": "Daten", - "stat_links": "Links", - "stat_tags": "Tags", - "stat_folders": "Ordner", - "section_export": "Daten exportieren", - "export_hint": "Alle Links, Tags und Ordner als JSON-Datei herunterladen.", - "action_export": "JSON exportieren", - "toast_exported": "Export heruntergeladen", - "section_danger": "Gefahrenzone", - "danger_hint": "Löscht alle lokalen uLoad-Daten (Links, Tags, Ordner). Synchronisierte Daten auf dem Server bleiben erhalten.", - "action_clear": "Alle Daten löschen", - "confirm_clear": "Alle lokalen uLoad-Daten löschen? Dies kann nicht rückgängig gemacht werden.", - "toast_cleared": "Alle uLoad-Daten gelöscht" - }, - "tags_route": { - "heading": "Tags", - "hide_form": "Ausblenden", - "show_form": "+ Neuer Tag", - "label_name": "Name", - "placeholder_name": "z.B. Social Media", - "label_color": "Farbe", - "action_create": "Erstellen", - "empty_title": "Noch keine Tags", - "empty_desc": "Erstelle Tags um deine Links zu organisieren.", - "links_count": "{count} Links", - "toast_created": "Tag \"{name}\" erstellt", - "toast_deleted": "Tag \"{name}\" gelöscht", - "toast_updated": "Tag aktualisiert" - } -} diff --git a/apps/mana/apps/web/src/lib/i18n/locales/uload/en.json b/apps/mana/apps/web/src/lib/i18n/locales/uload/en.json deleted file mode 100644 index 893e8ad86..000000000 --- a/apps/mana/apps/web/src/lib/i18n/locales/uload/en.json +++ /dev/null @@ -1,286 +0,0 @@ -{ - "nav": { - "links": "Links", - "tags": "Tags", - "analytics": "Analytics", - "settings": "Settings" - }, - "links": { - "title": "Links", - "newLink": "New Link", - "hide": "Hide", - "url": "URL", - "urlPlaceholder": "https://example.com/long-url-here", - "titleLabel": "Title (optional)", - "titlePlaceholder": "My Link", - "customCode": "Custom Code (optional)", - "customCodePlaceholder": "my-link", - "utmParams": "UTM Parameters", - "create": "Create Link", - "search": "Search links...", - "all": "All", - "active": "Active", - "inactive": "Inactive", - "allFolders": "All Folders", - "noLinks": "No links yet", - "noLinksDesc": "Create your first shortened link!", - "copied": "Link copied!", - "created": "Link created", - "updated": "Link updated", - "deleted": "Link deleted", - "edit": "Edit", - "editTitle": "Edit Link", - "save": "Save", - "cancel": "Cancel", - "delete": "Delete", - "deleteConfirm": "really delete?", - "activate": "Activate", - "deactivate": "Deactivate", - "copyLink": "Copy link", - "qrCode": "QR Code", - "qrDownload": "Download QR", - "clicks": "clicks" - }, - "tags": { - "title": "Tags", - "newTag": "New Tag", - "name": "Name", - "namePlaceholder": "e.g. Social Media", - "color": "Color", - "create": "Create", - "noTags": "No tags yet", - "noTagsDesc": "Create tags to organize your links.", - "created": "Tag created", - "updated": "Tag updated", - "deleted": "Tag deleted", - "linksCount": "Links" - }, - "analytics": { - "title": "Analytics", - "clicks": "Clicks", - "unique": "Unique", - "status": "Status", - "created": "Created", - "clicksOverTime": "Clicks over time", - "devices": "Devices", - "referrers": "Referrers", - "countries": "Countries", - "noData": "No data", - "noDataPeriod": "No data for this period yet", - "authRequired": "Analytics only for logged-in users", - "localClicks": "Local click counts", - "unknown": "Unknown", - "direct": "Direct" - }, - "settings": { - "title": "Settings", - "account": "Account", - "email": "Email", - "name": "Name", - "data": "Data", - "clearData": "Clear local data", - "clearConfirm": "Clear all local data? This cannot be undone.", - "cleared": "Local data cleared", - "logout": "Sign out", - "guestHint": "You are in guest mode.", - "loginToSync": "Sign in to sync your data." - }, - "common": { - "back": "Back", - "login": "Sign in", - "source": "Source", - "medium": "Medium", - "campaign": "Campaign" - }, - "list_view": { - "empty_title": "No links", - "add_placeholder": "Paste URL...", - "err_invalid_url": "Invalid URL", - "header_links": "{count} links", - "header_clicks": "{count} clicks", - "header_folders": "{count} folders", - "add_button": "New link" - }, - "detail_view": { - "not_found": "Link not found", - "confirm_delete": "Really delete link?", - "deleted_toast": "Link deleted", - "placeholder_title": "Title...", - "label_url": "URL", - "label_short_code": "Short code", - "label_short_code_legacy": "Short Code", - "placeholder_short_code": "custom-code", - "label_active": "Active", - "yes": "Yes", - "no": "No", - "label_clicks": "Clicks", - "label_expires_at": "Expires at", - "section_description": "Description", - "placeholder_description": "Add description...", - "meta_created": "Created: {date}", - "meta_updated": "Edited: {date}" - }, - "page": { - "title": "uLoad - Mana", - "all_links": "All links", - "counts": "{links} links · {folders} folders", - "counts_no_folders": "{links} links", - "hide_form": "- Hide", - "show_form": "+ New link", - "err_invalid_url_input": "Please enter a valid URL (with https://)", - "err_invalid_custom_code": "Custom code may only contain letters, numbers, - and _", - "err_short_code_taken": "Short code \"{code}\" is already taken", - "err_max_clicks": "Max clicks must be at least 1", - "err_expires_past": "Expiry date must be in the future", - "toast_created": "Link created: {code}", - "toast_updated": "Link updated", - "confirm_delete": "Really delete \"{name}\"?", - "toast_deleted": "Link deleted", - "toast_copied": "Link copied!", - "label_title": "Title (optional)", - "placeholder_title": "My link", - "label_custom_code": "Custom code (optional)", - "placeholder_custom_code": "my-link", - "section_advanced": "Advanced", - "label_expires": "Expires at", - "label_password": "Password", - "placeholder_optional": "Optional", - "label_max_clicks": "Max clicks", - "placeholder_unlimited": "Unlimited", - "section_utm": "UTM parameters", - "label_source": "Source", - "placeholder_source": "newsletter", - "label_medium": "Medium", - "placeholder_medium": "email", - "label_campaign": "Campaign", - "placeholder_campaign": "spring-2026", - "action_create": "Create link", - "placeholder_search": "Search links...", - "option_all": "All", - "option_active": "Active", - "option_inactive": "Inactive", - "option_all_folders": "All folders", - "empty_title": "No links yet", - "empty_desc": "Create your first shortened link!", - "badge_utm": "UTM", - "badge_password": "Password", - "badge_expires": "Expires", - "badge_expires_title": "Expires: {date}", - "action_analytics_title": "Analytics", - "action_copy_title": "Copy link", - "action_qr_title": "QR code", - "action_edit_title": "Edit", - "action_activate_title": "Activate", - "action_deactivate_title": "Deactivate", - "action_delete_title": "Delete", - "modal_edit_title": "Edit link", - "label_url_modal": "URL", - "label_title_modal": "Title", - "label_short_code_modal": "Short code", - "short_code_locked": "(not changeable)", - "action_cancel": "Cancel", - "action_save": "Save", - "modal_qr_title": "QR code", - "qr_alt": "QR code for {code}", - "action_copy_link": "Copy link", - "action_download_qr": "Download QR" - }, - "links_route": { - "title": "All links - uLoad - Mana", - "heading": "All links", - "action_back_title": "Back", - "action_select_done": "Done", - "action_select_start": "Select", - "placeholder_search": "Search links...", - "option_all": "All", - "option_active": "Active", - "option_inactive": "Inactive", - "option_all_folders": "All folders", - "selected_count": "{count} selected", - "action_bulk_toggle": "Activate/Deactivate", - "action_bulk_delete": "Delete", - "confirm_bulk_delete": "Delete {count} link(s)?", - "toast_bulk_deleted": "{count} links deleted", - "toast_bulk_updated": "{count} links updated", - "empty_title": "No links found", - "empty_filtered": "Try different filter settings.", - "empty_root": "Create links on the uLoad main page.", - "action_copy_title": "Copy link", - "action_activate_title": "Activate", - "action_deactivate_title": "Deactivate", - "action_delete_title": "Delete", - "action_analytics_title": "Analytics", - "toast_copied": "Link copied!", - "confirm_delete_single": "Really delete \"{name}\"?", - "toast_deleted_single": "Link deleted" - }, - "analytics_route": { - "title": "Analytics - uLoad - Mana", - "page_title": "Link", - "action_back_title": "Back", - "heading": "Analytics", - "not_found": "Link not found", - "stat_clicks": "Clicks", - "stat_unique": "Unique", - "stat_status": "Status", - "status_active": "Active", - "status_inactive": "Inactive", - "stat_created": "Created", - "section_details": "Link details", - "label_target_url": "Target URL", - "label_title": "Title", - "label_utm_params": "UTM parameters", - "utm_source": "Source:", - "utm_medium": "Medium:", - "utm_campaign": "Campaign:", - "label_expires_at": "Expires at", - "label_max_clicks": "Max clicks", - "max_clicks_value": "{used} / {max}", - "label_password_protected": "Password protected", - "yes": "Yes", - "section_timeline": "Clicks over time", - "days_unit": "{days}d", - "hint_no_server": "Detailed analytics are available when the uLoad server is connected.", - "hint_local_count": "Local click count: {count}", - "empty_period": "No data for this period yet", - "section_devices": "Devices", - "unknown": "Unknown", - "empty_no_data": "No data", - "section_referrers": "Referrers", - "direct": "Direct", - "section_countries": "Countries" - }, - "settings_route": { - "title": "uLoad settings — Mana", - "heading": "uLoad settings", - "subtitle": "Data overview · Export · Danger zone", - "section_data": "Data", - "stat_links": "Links", - "stat_tags": "Tags", - "stat_folders": "Folders", - "section_export": "Export data", - "export_hint": "Download all links, tags and folders as a JSON file.", - "action_export": "Export JSON", - "toast_exported": "Export downloaded", - "section_danger": "Danger zone", - "danger_hint": "Clears all local uLoad data (links, tags, folders). Data synced to the server stays.", - "action_clear": "Clear all data", - "confirm_clear": "Clear all local uLoad data? This cannot be undone.", - "toast_cleared": "All uLoad data cleared" - }, - "tags_route": { - "heading": "Tags", - "hide_form": "Hide", - "show_form": "+ New tag", - "label_name": "Name", - "placeholder_name": "e.g. Social Media", - "label_color": "Color", - "action_create": "Create", - "empty_title": "No tags yet", - "empty_desc": "Create tags to organize your links.", - "links_count": "{count} links", - "toast_created": "Tag \"{name}\" created", - "toast_deleted": "Tag \"{name}\" deleted", - "toast_updated": "Tag updated" - } -} diff --git a/apps/mana/apps/web/src/lib/i18n/locales/uload/es.json b/apps/mana/apps/web/src/lib/i18n/locales/uload/es.json deleted file mode 100644 index 8541a5a2b..000000000 --- a/apps/mana/apps/web/src/lib/i18n/locales/uload/es.json +++ /dev/null @@ -1,286 +0,0 @@ -{ - "nav": { - "links": "Enlaces", - "tags": "Etiquetas", - "analytics": "Analiticas", - "settings": "Ajustes" - }, - "links": { - "title": "Enlaces", - "newLink": "Nuevo enlace", - "hide": "Ocultar", - "url": "URL", - "urlPlaceholder": "https://example.com/url-larga", - "titleLabel": "Titulo (opcional)", - "titlePlaceholder": "Mi enlace", - "customCode": "Codigo personalizado (opcional)", - "customCodePlaceholder": "mi-enlace", - "utmParams": "Parametros UTM", - "create": "Crear enlace", - "search": "Buscar enlaces...", - "all": "Todos", - "active": "Activos", - "inactive": "Inactivos", - "allFolders": "Todas las carpetas", - "noLinks": "Sin enlaces aun", - "noLinksDesc": "Crea tu primer enlace acortado!", - "copied": "Enlace copiado!", - "created": "Enlace creado", - "updated": "Enlace actualizado", - "deleted": "Enlace eliminado", - "edit": "Editar", - "editTitle": "Editar enlace", - "save": "Guardar", - "cancel": "Cancelar", - "delete": "Eliminar", - "deleteConfirm": "eliminar?", - "activate": "Activar", - "deactivate": "Desactivar", - "copyLink": "Copiar enlace", - "qrCode": "Codigo QR", - "qrDownload": "Descargar QR", - "clicks": "clics" - }, - "tags": { - "title": "Etiquetas", - "newTag": "Nueva etiqueta", - "name": "Nombre", - "namePlaceholder": "ej. Redes sociales", - "color": "Color", - "create": "Crear", - "noTags": "Sin etiquetas", - "noTagsDesc": "Crea etiquetas para organizar tus enlaces.", - "created": "Etiqueta creada", - "updated": "Etiqueta actualizada", - "deleted": "Etiqueta eliminada", - "linksCount": "Enlaces" - }, - "analytics": { - "title": "Analiticas", - "clicks": "Clics", - "unique": "Unicos", - "status": "Estado", - "created": "Creado", - "clicksOverTime": "Clics en el tiempo", - "devices": "Dispositivos", - "referrers": "Referentes", - "countries": "Paises", - "noData": "Sin datos", - "noDataPeriod": "Sin datos para este periodo", - "authRequired": "Analiticas solo para usuarios registrados", - "localClicks": "Clics locales", - "unknown": "Desconocido", - "direct": "Directo" - }, - "settings": { - "title": "Ajustes", - "account": "Cuenta", - "email": "Email", - "name": "Nombre", - "data": "Datos", - "clearData": "Borrar datos locales", - "clearConfirm": "Borrar todos los datos locales?", - "cleared": "Datos locales borrados", - "logout": "Cerrar sesion", - "guestHint": "Estas en modo invitado.", - "loginToSync": "Inicia sesion para sincronizar." - }, - "common": { - "back": "Atras", - "login": "Iniciar sesion", - "source": "Fuente", - "medium": "Medio", - "campaign": "Campana" - }, - "list_view": { - "empty_title": "Sin enlaces", - "add_placeholder": "Pega URL...", - "err_invalid_url": "URL no válida", - "header_links": "{count} enlaces", - "header_clicks": "{count} clics", - "header_folders": "{count} carpetas", - "add_button": "Nuevo enlace" - }, - "detail_view": { - "not_found": "Enlace no encontrado", - "confirm_delete": "¿Eliminar realmente el enlace?", - "deleted_toast": "Enlace eliminado", - "placeholder_title": "Título...", - "label_url": "URL", - "label_short_code": "Código corto", - "label_short_code_legacy": "Short Code", - "placeholder_short_code": "codigo-personal", - "label_active": "Activo", - "yes": "Sí", - "no": "No", - "label_clicks": "Clics", - "label_expires_at": "Caduca", - "section_description": "Descripción", - "placeholder_description": "Añadir descripción...", - "meta_created": "Creado: {date}", - "meta_updated": "Editado: {date}" - }, - "page": { - "title": "uLoad - Mana", - "all_links": "Todos los enlaces", - "counts": "{links} enlaces · {folders} carpetas", - "counts_no_folders": "{links} enlaces", - "hide_form": "- Ocultar", - "show_form": "+ Nuevo enlace", - "err_invalid_url_input": "Introduce una URL válida (con https://)", - "err_invalid_custom_code": "El código personal solo puede tener letras, números, - y _", - "err_short_code_taken": "El código \"{code}\" ya está en uso", - "err_max_clicks": "Max clics debe ser al menos 1", - "err_expires_past": "La fecha de caducidad debe estar en el futuro", - "toast_created": "Enlace creado: {code}", - "toast_updated": "Enlace actualizado", - "confirm_delete": "¿Eliminar realmente \"{name}\"?", - "toast_deleted": "Enlace eliminado", - "toast_copied": "Enlace copiado!", - "label_title": "Título (opcional)", - "placeholder_title": "Mi enlace", - "label_custom_code": "Código personal (opcional)", - "placeholder_custom_code": "mi-enlace", - "section_advanced": "Avanzado", - "label_expires": "Fecha de caducidad", - "label_password": "Contraseña", - "placeholder_optional": "Opcional", - "label_max_clicks": "Max clics", - "placeholder_unlimited": "Ilimitado", - "section_utm": "Parámetros UTM", - "label_source": "Source", - "placeholder_source": "newsletter", - "label_medium": "Medium", - "placeholder_medium": "email", - "label_campaign": "Campaign", - "placeholder_campaign": "spring-2026", - "action_create": "Crear enlace", - "placeholder_search": "Buscar enlaces...", - "option_all": "Todos", - "option_active": "Activos", - "option_inactive": "Inactivos", - "option_all_folders": "Todas las carpetas", - "empty_title": "Sin enlaces", - "empty_desc": "¡Crea tu primer enlace acortado!", - "badge_utm": "UTM", - "badge_password": "Contraseña", - "badge_expires": "Caducidad", - "badge_expires_title": "Caduca: {date}", - "action_analytics_title": "Analíticas", - "action_copy_title": "Copiar enlace", - "action_qr_title": "Código QR", - "action_edit_title": "Editar", - "action_activate_title": "Activar", - "action_deactivate_title": "Desactivar", - "action_delete_title": "Eliminar", - "modal_edit_title": "Editar enlace", - "label_url_modal": "URL", - "label_title_modal": "Título", - "label_short_code_modal": "Código corto", - "short_code_locked": "(no modificable)", - "action_cancel": "Cancelar", - "action_save": "Guardar", - "modal_qr_title": "Código QR", - "qr_alt": "Código QR para {code}", - "action_copy_link": "Copiar enlace", - "action_download_qr": "Descargar QR" - }, - "links_route": { - "title": "Todos los enlaces - uLoad - Mana", - "heading": "Todos los enlaces", - "action_back_title": "Atrás", - "action_select_done": "Listo", - "action_select_start": "Seleccionar", - "placeholder_search": "Buscar enlaces...", - "option_all": "Todos", - "option_active": "Activos", - "option_inactive": "Inactivos", - "option_all_folders": "Todas las carpetas", - "selected_count": "{count} seleccionados", - "action_bulk_toggle": "Activar/Desactivar", - "action_bulk_delete": "Eliminar", - "confirm_bulk_delete": "¿Eliminar {count} enlace(s)?", - "toast_bulk_deleted": "{count} enlaces eliminados", - "toast_bulk_updated": "{count} enlaces actualizados", - "empty_title": "No se encontraron enlaces", - "empty_filtered": "Prueba otros filtros.", - "empty_root": "Crea enlaces en la página principal de uLoad.", - "action_copy_title": "Copiar enlace", - "action_activate_title": "Activar", - "action_deactivate_title": "Desactivar", - "action_delete_title": "Eliminar", - "action_analytics_title": "Analíticas", - "toast_copied": "Enlace copiado!", - "confirm_delete_single": "¿Eliminar realmente \"{name}\"?", - "toast_deleted_single": "Enlace eliminado" - }, - "analytics_route": { - "title": "Analíticas - uLoad - Mana", - "page_title": "Enlace", - "action_back_title": "Atrás", - "heading": "Analíticas", - "not_found": "Enlace no encontrado", - "stat_clicks": "Clics", - "stat_unique": "Únicos", - "stat_status": "Estado", - "status_active": "Activo", - "status_inactive": "Inactivo", - "stat_created": "Creado", - "section_details": "Detalles del enlace", - "label_target_url": "URL destino", - "label_title": "Título", - "label_utm_params": "Parámetros UTM", - "utm_source": "Source:", - "utm_medium": "Medium:", - "utm_campaign": "Campaign:", - "label_expires_at": "Caduca", - "label_max_clicks": "Max clics", - "max_clicks_value": "{used} / {max}", - "label_password_protected": "Con contraseña", - "yes": "Sí", - "section_timeline": "Clics en el tiempo", - "days_unit": "{days}d", - "hint_no_server": "Las analíticas detalladas están disponibles cuando el servidor uLoad está conectado.", - "hint_local_count": "Clics locales: {count}", - "empty_period": "Aún no hay datos para este periodo", - "section_devices": "Dispositivos", - "unknown": "Desconocido", - "empty_no_data": "Sin datos", - "section_referrers": "Referentes", - "direct": "Directo", - "section_countries": "Países" - }, - "settings_route": { - "title": "Ajustes uLoad — Mana", - "heading": "Ajustes uLoad", - "subtitle": "Resumen de datos · Exportar · Zona peligrosa", - "section_data": "Datos", - "stat_links": "Enlaces", - "stat_tags": "Etiquetas", - "stat_folders": "Carpetas", - "section_export": "Exportar datos", - "export_hint": "Descarga todos los enlaces, etiquetas y carpetas como JSON.", - "action_export": "Exportar JSON", - "toast_exported": "Exportación descargada", - "section_danger": "Zona peligrosa", - "danger_hint": "Borra todos los datos locales de uLoad (enlaces, etiquetas, carpetas). Los datos sincronizados con el servidor se conservan.", - "action_clear": "Borrar todos los datos", - "confirm_clear": "¿Borrar todos los datos locales de uLoad? Esto no se puede deshacer.", - "toast_cleared": "Todos los datos de uLoad borrados" - }, - "tags_route": { - "heading": "Etiquetas", - "hide_form": "Ocultar", - "show_form": "+ Nueva etiqueta", - "label_name": "Nombre", - "placeholder_name": "ej. Redes sociales", - "label_color": "Color", - "action_create": "Crear", - "empty_title": "Sin etiquetas", - "empty_desc": "Crea etiquetas para organizar tus enlaces.", - "links_count": "{count} enlaces", - "toast_created": "Etiqueta \"{name}\" creada", - "toast_deleted": "Etiqueta \"{name}\" eliminada", - "toast_updated": "Etiqueta actualizada" - } -} diff --git a/apps/mana/apps/web/src/lib/i18n/locales/uload/fr.json b/apps/mana/apps/web/src/lib/i18n/locales/uload/fr.json deleted file mode 100644 index 59c35176b..000000000 --- a/apps/mana/apps/web/src/lib/i18n/locales/uload/fr.json +++ /dev/null @@ -1,286 +0,0 @@ -{ - "nav": { - "links": "Liens", - "tags": "Tags", - "analytics": "Analytiques", - "settings": "Parametres" - }, - "links": { - "title": "Liens", - "newLink": "Nouveau lien", - "hide": "Masquer", - "url": "URL", - "urlPlaceholder": "https://example.com/url-longue", - "titleLabel": "Titre (optionnel)", - "titlePlaceholder": "Mon lien", - "customCode": "Code personnalise (optionnel)", - "customCodePlaceholder": "mon-lien", - "utmParams": "Parametres UTM", - "create": "Creer le lien", - "search": "Rechercher des liens...", - "all": "Tous", - "active": "Actifs", - "inactive": "Inactifs", - "allFolders": "Tous les dossiers", - "noLinks": "Aucun lien", - "noLinksDesc": "Creez votre premier lien raccourci !", - "copied": "Lien copie !", - "created": "Lien cree", - "updated": "Lien mis a jour", - "deleted": "Lien supprime", - "edit": "Modifier", - "editTitle": "Modifier le lien", - "save": "Enregistrer", - "cancel": "Annuler", - "delete": "Supprimer", - "deleteConfirm": "supprimer ?", - "activate": "Activer", - "deactivate": "Desactiver", - "copyLink": "Copier le lien", - "qrCode": "Code QR", - "qrDownload": "Telecharger le QR", - "clicks": "clics" - }, - "tags": { - "title": "Tags", - "newTag": "Nouveau tag", - "name": "Nom", - "namePlaceholder": "ex. Reseaux sociaux", - "color": "Couleur", - "create": "Creer", - "noTags": "Aucun tag", - "noTagsDesc": "Creez des tags pour organiser vos liens.", - "created": "Tag cree", - "updated": "Tag mis a jour", - "deleted": "Tag supprime", - "linksCount": "Liens" - }, - "analytics": { - "title": "Analytiques", - "clicks": "Clics", - "unique": "Uniques", - "status": "Statut", - "created": "Cree", - "clicksOverTime": "Clics dans le temps", - "devices": "Appareils", - "referrers": "Referents", - "countries": "Pays", - "noData": "Aucune donnee", - "noDataPeriod": "Aucune donnee pour cette periode", - "authRequired": "Analytiques pour utilisateurs connectes", - "localClicks": "Clics locaux", - "unknown": "Inconnu", - "direct": "Direct" - }, - "settings": { - "title": "Parametres", - "account": "Compte", - "email": "Email", - "name": "Nom", - "data": "Donnees", - "clearData": "Effacer les donnees locales", - "clearConfirm": "Effacer toutes les donnees ?", - "cleared": "Donnees effacees", - "logout": "Deconnexion", - "guestHint": "Vous etes en mode invite.", - "loginToSync": "Connectez-vous pour synchroniser." - }, - "common": { - "back": "Retour", - "login": "Se connecter", - "source": "Source", - "medium": "Medium", - "campaign": "Campagne" - }, - "list_view": { - "empty_title": "Aucun lien", - "add_placeholder": "Coller URL...", - "err_invalid_url": "URL invalide", - "header_links": "{count} liens", - "header_clicks": "{count} clics", - "header_folders": "{count} dossiers", - "add_button": "Nouveau lien" - }, - "detail_view": { - "not_found": "Lien introuvable", - "confirm_delete": "Vraiment supprimer ce lien ?", - "deleted_toast": "Lien supprimé", - "placeholder_title": "Titre...", - "label_url": "URL", - "label_short_code": "Code court", - "label_short_code_legacy": "Short Code", - "placeholder_short_code": "code-personnalise", - "label_active": "Actif", - "yes": "Oui", - "no": "Non", - "label_clicks": "Clics", - "label_expires_at": "Expire le", - "section_description": "Description", - "placeholder_description": "Ajouter une description...", - "meta_created": "Créé : {date}", - "meta_updated": "Modifié : {date}" - }, - "page": { - "title": "uLoad - Mana", - "all_links": "Tous les liens", - "counts": "{links} liens · {folders} dossiers", - "counts_no_folders": "{links} liens", - "hide_form": "- Masquer", - "show_form": "+ Nouveau lien", - "err_invalid_url_input": "Veuillez saisir une URL valide (avec https://)", - "err_invalid_custom_code": "Le code personnalisé ne peut contenir que des lettres, chiffres, - et _", - "err_short_code_taken": "Le code \"{code}\" est déjà utilisé", - "err_max_clicks": "Max clics doit être au moins 1", - "err_expires_past": "La date d'expiration doit être dans le futur", - "toast_created": "Lien créé : {code}", - "toast_updated": "Lien mis à jour", - "confirm_delete": "Vraiment supprimer \"{name}\" ?", - "toast_deleted": "Lien supprimé", - "toast_copied": "Lien copié !", - "label_title": "Titre (optionnel)", - "placeholder_title": "Mon lien", - "label_custom_code": "Code personnalisé (optionnel)", - "placeholder_custom_code": "mon-lien", - "section_advanced": "Avancé", - "label_expires": "Date d'expiration", - "label_password": "Mot de passe", - "placeholder_optional": "Optionnel", - "label_max_clicks": "Max clics", - "placeholder_unlimited": "Illimité", - "section_utm": "Paramètres UTM", - "label_source": "Source", - "placeholder_source": "newsletter", - "label_medium": "Medium", - "placeholder_medium": "email", - "label_campaign": "Campaign", - "placeholder_campaign": "spring-2026", - "action_create": "Créer le lien", - "placeholder_search": "Rechercher des liens...", - "option_all": "Tous", - "option_active": "Actifs", - "option_inactive": "Inactifs", - "option_all_folders": "Tous les dossiers", - "empty_title": "Aucun lien", - "empty_desc": "Créez votre premier lien raccourci !", - "badge_utm": "UTM", - "badge_password": "Mot de passe", - "badge_expires": "Expiration", - "badge_expires_title": "Expire : {date}", - "action_analytics_title": "Analytiques", - "action_copy_title": "Copier le lien", - "action_qr_title": "Code QR", - "action_edit_title": "Modifier", - "action_activate_title": "Activer", - "action_deactivate_title": "Désactiver", - "action_delete_title": "Supprimer", - "modal_edit_title": "Modifier le lien", - "label_url_modal": "URL", - "label_title_modal": "Titre", - "label_short_code_modal": "Code court", - "short_code_locked": "(non modifiable)", - "action_cancel": "Annuler", - "action_save": "Enregistrer", - "modal_qr_title": "Code QR", - "qr_alt": "Code QR pour {code}", - "action_copy_link": "Copier le lien", - "action_download_qr": "Télécharger le QR" - }, - "links_route": { - "title": "Tous les liens - uLoad - Mana", - "heading": "Tous les liens", - "action_back_title": "Retour", - "action_select_done": "Terminé", - "action_select_start": "Sélectionner", - "placeholder_search": "Rechercher des liens...", - "option_all": "Tous", - "option_active": "Actifs", - "option_inactive": "Inactifs", - "option_all_folders": "Tous les dossiers", - "selected_count": "{count} sélectionnés", - "action_bulk_toggle": "Activer/Désactiver", - "action_bulk_delete": "Supprimer", - "confirm_bulk_delete": "Supprimer {count} lien(s) ?", - "toast_bulk_deleted": "{count} liens supprimés", - "toast_bulk_updated": "{count} liens mis à jour", - "empty_title": "Aucun lien trouvé", - "empty_filtered": "Essaie d'autres filtres.", - "empty_root": "Crée des liens sur la page principale uLoad.", - "action_copy_title": "Copier le lien", - "action_activate_title": "Activer", - "action_deactivate_title": "Désactiver", - "action_delete_title": "Supprimer", - "action_analytics_title": "Analytiques", - "toast_copied": "Lien copié !", - "confirm_delete_single": "Vraiment supprimer \"{name}\" ?", - "toast_deleted_single": "Lien supprimé" - }, - "analytics_route": { - "title": "Analytiques - uLoad - Mana", - "page_title": "Lien", - "action_back_title": "Retour", - "heading": "Analytiques", - "not_found": "Lien introuvable", - "stat_clicks": "Clics", - "stat_unique": "Uniques", - "stat_status": "Statut", - "status_active": "Actif", - "status_inactive": "Inactif", - "stat_created": "Créé", - "section_details": "Détails du lien", - "label_target_url": "URL cible", - "label_title": "Titre", - "label_utm_params": "Paramètres UTM", - "utm_source": "Source :", - "utm_medium": "Medium :", - "utm_campaign": "Campaign :", - "label_expires_at": "Expire le", - "label_max_clicks": "Max clics", - "max_clicks_value": "{used} / {max}", - "label_password_protected": "Protégé par mot de passe", - "yes": "Oui", - "section_timeline": "Clics dans le temps", - "days_unit": "{days}j", - "hint_no_server": "Les analytiques détaillées sont disponibles quand le serveur uLoad est connecté.", - "hint_local_count": "Clics locaux : {count}", - "empty_period": "Aucune donnée pour cette période", - "section_devices": "Appareils", - "unknown": "Inconnu", - "empty_no_data": "Aucune donnée", - "section_referrers": "Référents", - "direct": "Direct", - "section_countries": "Pays" - }, - "settings_route": { - "title": "Paramètres uLoad — Mana", - "heading": "Paramètres uLoad", - "subtitle": "Aperçu des données · Export · Zone dangereuse", - "section_data": "Données", - "stat_links": "Liens", - "stat_tags": "Tags", - "stat_folders": "Dossiers", - "section_export": "Exporter les données", - "export_hint": "Téléchargez tous les liens, tags et dossiers en JSON.", - "action_export": "Exporter JSON", - "toast_exported": "Export téléchargé", - "section_danger": "Zone dangereuse", - "danger_hint": "Efface toutes les données locales uLoad (liens, tags, dossiers). Les données synchronisées sur le serveur restent.", - "action_clear": "Effacer toutes les données", - "confirm_clear": "Effacer toutes les données locales uLoad ? Cela ne peut pas être annulé.", - "toast_cleared": "Toutes les données uLoad effacées" - }, - "tags_route": { - "heading": "Tags", - "hide_form": "Masquer", - "show_form": "+ Nouveau tag", - "label_name": "Nom", - "placeholder_name": "ex. Réseaux sociaux", - "label_color": "Couleur", - "action_create": "Créer", - "empty_title": "Aucun tag", - "empty_desc": "Crée des tags pour organiser tes liens.", - "links_count": "{count} liens", - "toast_created": "Tag \"{name}\" créé", - "toast_deleted": "Tag \"{name}\" supprimé", - "toast_updated": "Tag mis à jour" - } -} diff --git a/apps/mana/apps/web/src/lib/i18n/locales/uload/it.json b/apps/mana/apps/web/src/lib/i18n/locales/uload/it.json deleted file mode 100644 index 24ebb38fc..000000000 --- a/apps/mana/apps/web/src/lib/i18n/locales/uload/it.json +++ /dev/null @@ -1,286 +0,0 @@ -{ - "nav": { - "links": "Link", - "tags": "Tag", - "analytics": "Analisi", - "settings": "Impostazioni" - }, - "links": { - "title": "Link", - "newLink": "Nuovo link", - "hide": "Nascondi", - "url": "URL", - "urlPlaceholder": "https://example.com/url-lungo", - "titleLabel": "Titolo (opzionale)", - "titlePlaceholder": "Il mio link", - "customCode": "Codice personalizzato (opzionale)", - "customCodePlaceholder": "mio-link", - "utmParams": "Parametri UTM", - "create": "Crea link", - "search": "Cerca link...", - "all": "Tutti", - "active": "Attivi", - "inactive": "Inattivi", - "allFolders": "Tutte le cartelle", - "noLinks": "Nessun link", - "noLinksDesc": "Crea il tuo primo link accorciato!", - "copied": "Link copiato!", - "created": "Link creato", - "updated": "Link aggiornato", - "deleted": "Link eliminato", - "edit": "Modifica", - "editTitle": "Modifica link", - "save": "Salva", - "cancel": "Annulla", - "delete": "Elimina", - "deleteConfirm": "eliminare?", - "activate": "Attiva", - "deactivate": "Disattiva", - "copyLink": "Copia link", - "qrCode": "Codice QR", - "qrDownload": "Scarica QR", - "clicks": "clic" - }, - "tags": { - "title": "Tag", - "newTag": "Nuovo tag", - "name": "Nome", - "namePlaceholder": "es. Social media", - "color": "Colore", - "create": "Crea", - "noTags": "Nessun tag", - "noTagsDesc": "Crea tag per organizzare i tuoi link.", - "created": "Tag creato", - "updated": "Tag aggiornato", - "deleted": "Tag eliminato", - "linksCount": "Link" - }, - "analytics": { - "title": "Analisi", - "clicks": "Clic", - "unique": "Unici", - "status": "Stato", - "created": "Creato", - "clicksOverTime": "Clic nel tempo", - "devices": "Dispositivi", - "referrers": "Referenti", - "countries": "Paesi", - "noData": "Nessun dato", - "noDataPeriod": "Nessun dato per questo periodo", - "authRequired": "Analisi solo per utenti registrati", - "localClicks": "Clic locali", - "unknown": "Sconosciuto", - "direct": "Diretto" - }, - "settings": { - "title": "Impostazioni", - "account": "Account", - "email": "Email", - "name": "Nome", - "data": "Dati", - "clearData": "Cancella dati locali", - "clearConfirm": "Cancellare tutti i dati?", - "cleared": "Dati cancellati", - "logout": "Esci", - "guestHint": "Sei in modalita ospite.", - "loginToSync": "Accedi per sincronizzare." - }, - "common": { - "back": "Indietro", - "login": "Accedi", - "source": "Sorgente", - "medium": "Mezzo", - "campaign": "Campagna" - }, - "list_view": { - "empty_title": "Nessun link", - "add_placeholder": "Incolla URL...", - "err_invalid_url": "URL non valido", - "header_links": "{count} link", - "header_clicks": "{count} clic", - "header_folders": "{count} cartelle", - "add_button": "Nuovo link" - }, - "detail_view": { - "not_found": "Link non trovato", - "confirm_delete": "Eliminare davvero il link?", - "deleted_toast": "Link eliminato", - "placeholder_title": "Titolo...", - "label_url": "URL", - "label_short_code": "Codice breve", - "label_short_code_legacy": "Short Code", - "placeholder_short_code": "codice-personale", - "label_active": "Attivo", - "yes": "Sì", - "no": "No", - "label_clicks": "Clic", - "label_expires_at": "Scadenza", - "section_description": "Descrizione", - "placeholder_description": "Aggiungi descrizione...", - "meta_created": "Creato: {date}", - "meta_updated": "Modificato: {date}" - }, - "page": { - "title": "uLoad - Mana", - "all_links": "Tutti i link", - "counts": "{links} link · {folders} cartelle", - "counts_no_folders": "{links} link", - "hide_form": "- Nascondi", - "show_form": "+ Nuovo link", - "err_invalid_url_input": "Inserisci un URL valido (con https://)", - "err_invalid_custom_code": "Il codice può contenere solo lettere, numeri, - e _", - "err_short_code_taken": "Il codice \"{code}\" è già in uso", - "err_max_clicks": "Max clic deve essere almeno 1", - "err_expires_past": "La data di scadenza deve essere nel futuro", - "toast_created": "Link creato: {code}", - "toast_updated": "Link aggiornato", - "confirm_delete": "Eliminare davvero \"{name}\"?", - "toast_deleted": "Link eliminato", - "toast_copied": "Link copiato!", - "label_title": "Titolo (opzionale)", - "placeholder_title": "Il mio link", - "label_custom_code": "Codice personale (opzionale)", - "placeholder_custom_code": "mio-link", - "section_advanced": "Avanzato", - "label_expires": "Data di scadenza", - "label_password": "Password", - "placeholder_optional": "Opzionale", - "label_max_clicks": "Max clic", - "placeholder_unlimited": "Illimitato", - "section_utm": "Parametri UTM", - "label_source": "Source", - "placeholder_source": "newsletter", - "label_medium": "Medium", - "placeholder_medium": "email", - "label_campaign": "Campaign", - "placeholder_campaign": "spring-2026", - "action_create": "Crea link", - "placeholder_search": "Cerca link...", - "option_all": "Tutti", - "option_active": "Attivi", - "option_inactive": "Inattivi", - "option_all_folders": "Tutte le cartelle", - "empty_title": "Nessun link", - "empty_desc": "Crea il tuo primo link accorciato!", - "badge_utm": "UTM", - "badge_password": "Password", - "badge_expires": "Scadenza", - "badge_expires_title": "Scade: {date}", - "action_analytics_title": "Analisi", - "action_copy_title": "Copia link", - "action_qr_title": "Codice QR", - "action_edit_title": "Modifica", - "action_activate_title": "Attiva", - "action_deactivate_title": "Disattiva", - "action_delete_title": "Elimina", - "modal_edit_title": "Modifica link", - "label_url_modal": "URL", - "label_title_modal": "Titolo", - "label_short_code_modal": "Codice breve", - "short_code_locked": "(non modificabile)", - "action_cancel": "Annulla", - "action_save": "Salva", - "modal_qr_title": "Codice QR", - "qr_alt": "Codice QR per {code}", - "action_copy_link": "Copia link", - "action_download_qr": "Scarica QR" - }, - "links_route": { - "title": "Tutti i link - uLoad - Mana", - "heading": "Tutti i link", - "action_back_title": "Indietro", - "action_select_done": "Fatto", - "action_select_start": "Seleziona", - "placeholder_search": "Cerca link...", - "option_all": "Tutti", - "option_active": "Attivi", - "option_inactive": "Inattivi", - "option_all_folders": "Tutte le cartelle", - "selected_count": "{count} selezionati", - "action_bulk_toggle": "Attiva/Disattiva", - "action_bulk_delete": "Elimina", - "confirm_bulk_delete": "Eliminare {count} link?", - "toast_bulk_deleted": "{count} link eliminati", - "toast_bulk_updated": "{count} link aggiornati", - "empty_title": "Nessun link trovato", - "empty_filtered": "Prova altri filtri.", - "empty_root": "Crea link sulla pagina principale di uLoad.", - "action_copy_title": "Copia link", - "action_activate_title": "Attiva", - "action_deactivate_title": "Disattiva", - "action_delete_title": "Elimina", - "action_analytics_title": "Analisi", - "toast_copied": "Link copiato!", - "confirm_delete_single": "Eliminare davvero \"{name}\"?", - "toast_deleted_single": "Link eliminato" - }, - "analytics_route": { - "title": "Analisi - uLoad - Mana", - "page_title": "Link", - "action_back_title": "Indietro", - "heading": "Analisi", - "not_found": "Link non trovato", - "stat_clicks": "Clic", - "stat_unique": "Unici", - "stat_status": "Stato", - "status_active": "Attivo", - "status_inactive": "Inattivo", - "stat_created": "Creato", - "section_details": "Dettagli link", - "label_target_url": "URL di destinazione", - "label_title": "Titolo", - "label_utm_params": "Parametri UTM", - "utm_source": "Source:", - "utm_medium": "Medium:", - "utm_campaign": "Campaign:", - "label_expires_at": "Scade", - "label_max_clicks": "Max clic", - "max_clicks_value": "{used} / {max}", - "label_password_protected": "Protetto da password", - "yes": "Sì", - "section_timeline": "Clic nel tempo", - "days_unit": "{days}g", - "hint_no_server": "Le analisi dettagliate sono disponibili quando il server uLoad è connesso.", - "hint_local_count": "Clic locali: {count}", - "empty_period": "Nessun dato per questo periodo", - "section_devices": "Dispositivi", - "unknown": "Sconosciuto", - "empty_no_data": "Nessun dato", - "section_referrers": "Referenti", - "direct": "Diretto", - "section_countries": "Paesi" - }, - "settings_route": { - "title": "Impostazioni uLoad — Mana", - "heading": "Impostazioni uLoad", - "subtitle": "Riepilogo dati · Esporta · Zona pericolosa", - "section_data": "Dati", - "stat_links": "Link", - "stat_tags": "Tag", - "stat_folders": "Cartelle", - "section_export": "Esporta dati", - "export_hint": "Scarica tutti i link, tag e cartelle come JSON.", - "action_export": "Esporta JSON", - "toast_exported": "Esportazione scaricata", - "section_danger": "Zona pericolosa", - "danger_hint": "Cancella tutti i dati locali uLoad (link, tag, cartelle). I dati sincronizzati con il server restano.", - "action_clear": "Cancella tutti i dati", - "confirm_clear": "Cancellare tutti i dati locali uLoad? Non può essere annullato.", - "toast_cleared": "Tutti i dati uLoad cancellati" - }, - "tags_route": { - "heading": "Tag", - "hide_form": "Nascondi", - "show_form": "+ Nuovo tag", - "label_name": "Nome", - "placeholder_name": "es. Social media", - "label_color": "Colore", - "action_create": "Crea", - "empty_title": "Nessun tag", - "empty_desc": "Crea tag per organizzare i tuoi link.", - "links_count": "{count} link", - "toast_created": "Tag \"{name}\" creato", - "toast_deleted": "Tag \"{name}\" eliminato", - "toast_updated": "Tag aggiornato" - } -} diff --git a/apps/mana/apps/web/src/lib/modules/uload/ListView.svelte b/apps/mana/apps/web/src/lib/modules/uload/ListView.svelte deleted file mode 100644 index bdcfd900d..000000000 --- a/apps/mana/apps/web/src/lib/modules/uload/ListView.svelte +++ /dev/null @@ -1,242 +0,0 @@ - - - - l.id} emptyTitle={$_('uload.list_view.empty_title')}> - {#snippet header()} - {$_('uload.list_view.header_links', { values: { count: links.length } })} - {$_('uload.list_view.header_clicks', { values: { count: totalClicks } })} - {$_('uload.list_view.header_folders', { values: { count: folders.length } })} - {/snippet} - - {#snippet listHeader()} - {#if showAdd} -
{ - e.preventDefault(); - addLink(); - }} - class="quick-add" - > - - - - - - {#if error} -

{error}

- {/if} - {:else} - - {/if} - {/snippet} - - {#snippet item(link)} - - {/snippet} -
- - diff --git a/apps/mana/apps/web/src/lib/modules/uload/collections.ts b/apps/mana/apps/web/src/lib/modules/uload/collections.ts deleted file mode 100644 index 211677d71..000000000 --- a/apps/mana/apps/web/src/lib/modules/uload/collections.ts +++ /dev/null @@ -1,113 +0,0 @@ -/** - * uLoad module — collection accessors and guest seed data. - * - * Uses table names in the unified DB: links, uloadTags, uloadFolders, linkTags. - */ - -import { db } from '$lib/data/database'; -import type { LocalLink, LocalTag, LocalFolder, LocalLinkTag } from './types'; - -// ─── Collection Accessors ────────────────────────────────── - -export const linkTable = db.table('links'); -export const uloadTagTable = db.table('uloadTags'); -export const uloadFolderTable = db.table('uloadFolders'); -export const linkTagTable = db.table('linkTags'); - -// ─── Guest Seed ──────────────────────────────────────────── - -export const ULOAD_GUEST_SEED = { - uloadFolders: [ - { - id: 'folder-personal', - name: 'Persoenlich', - color: '#3b82f6', - order: 0, - }, - { - id: 'folder-work', - name: 'Arbeit', - color: '#10b981', - order: 1, - }, - ] satisfies LocalFolder[], - links: [ - { - id: 'link-welcome', - shortCode: 'welcome', - originalUrl: 'https://ulo.ad', - title: 'Willkommen bei uLoad!', - description: 'Dein erster gekuerzter Link.', - isActive: true, - clickCount: 42, - folderId: 'folder-personal', - order: 0, - }, - { - id: 'link-github', - shortCode: 'gh-demo', - originalUrl: 'https://github.com', - title: 'GitHub', - description: 'Beispiel-Link mit Tags', - isActive: true, - clickCount: 15, - folderId: 'folder-work', - order: 0, - }, - { - id: 'link-docs', - shortCode: 'docs', - originalUrl: 'https://docs.example.com/getting-started', - title: 'Dokumentation', - description: 'Link mit UTM-Tracking', - isActive: true, - clickCount: 8, - utmSource: 'newsletter', - utmMedium: 'email', - utmCampaign: 'onboarding', - folderId: 'folder-work', - order: 1, - }, - { - id: 'link-expired', - shortCode: 'old-promo', - originalUrl: 'https://example.com/promo', - title: 'Abgelaufene Promotion', - description: 'Dieser Link ist deaktiviert.', - isActive: false, - clickCount: 234, - folderId: 'folder-personal', - order: 1, - }, - ] satisfies LocalLink[], - uloadTags: [ - { - id: 'tag-social', - name: 'Social Media', - slug: 'social-media', - color: '#8b5cf6', - icon: null, - visibility: 'space', - usageCount: 0, - }, - { - id: 'tag-docs', - name: 'Dokumentation', - slug: 'dokumentation', - color: '#3b82f6', - icon: null, - visibility: 'space', - usageCount: 0, - }, - { - id: 'tag-marketing', - name: 'Marketing', - slug: 'marketing', - color: '#10b981', - icon: null, - visibility: 'space', - usageCount: 0, - }, - ] satisfies LocalTag[], - linkTags: [] as LocalLinkTag[], -}; diff --git a/apps/mana/apps/web/src/lib/modules/uload/index.ts b/apps/mana/apps/web/src/lib/modules/uload/index.ts deleted file mode 100644 index 0b33a1b52..000000000 --- a/apps/mana/apps/web/src/lib/modules/uload/index.ts +++ /dev/null @@ -1,33 +0,0 @@ -/** - * uLoad module — barrel exports. - */ - -export { - linkTable, - uloadTagTable, - uloadFolderTable, - linkTagTable, - ULOAD_GUEST_SEED, -} from './collections'; -export { - useAllLinks, - useAllTags, - useAllFolders, - useAllLinkTags, - useLinkById, - toLink, - toTag, - toFolder, - toLinkTag, - getFilteredLinks, - getSortedLinks, - getLinkById, - getTagById, - getFolderById, - getTagUsageCount, - getLinkTags, - generateShortCode, - slugify, -} from './queries'; -export type { LocalLink, LocalTag, LocalFolder, LocalLinkTag } from './types'; -export type { Link, Tag, Folder, LinkTag, StatusFilter, LinkFilterCriteria } from './queries'; diff --git a/apps/mana/apps/web/src/lib/modules/uload/module.config.ts b/apps/mana/apps/web/src/lib/modules/uload/module.config.ts deleted file mode 100644 index 82f8ac62b..000000000 --- a/apps/mana/apps/web/src/lib/modules/uload/module.config.ts +++ /dev/null @@ -1,11 +0,0 @@ -import type { ModuleConfig } from '$lib/data/module-registry'; - -export const uloadModuleConfig: ModuleConfig = { - appId: 'uload', - tables: [ - { name: 'links' }, - { name: 'uloadTags', syncName: 'tags' }, - { name: 'uloadFolders', syncName: 'folders' }, - { name: 'linkTags' }, - ], -}; diff --git a/apps/mana/apps/web/src/lib/modules/uload/queries.ts b/apps/mana/apps/web/src/lib/modules/uload/queries.ts deleted file mode 100644 index 56a8da301..000000000 --- a/apps/mana/apps/web/src/lib/modules/uload/queries.ts +++ /dev/null @@ -1,273 +0,0 @@ -/** - * Reactive Queries & Pure Helpers for uLoad module. - * - * Uses Dexie liveQuery to automatically re-render when IndexedDB changes - * (local writes, sync updates, other tabs). - */ - -import { liveQuery } from 'dexie'; -import { deriveUpdatedAt } from '$lib/data/sync'; -import { useScopedLiveQuery } from '$lib/data/scope/use-scoped-live-query.svelte'; -import { db } from '$lib/data/database'; -import { scopedForModule } from '$lib/data/scope'; -import { decryptRecord, decryptRecords } from '$lib/data/crypto'; -import type { LocalLink, LocalTag, LocalFolder, LocalLinkTag } from './types'; - -// ─── Shared View Types ──────────────────────────────────── - -export interface Link { - id: string; - shortCode: string; - customCode?: string; - originalUrl: string; - title?: string; - description?: string; - isActive: boolean; - password?: string; - maxClicks?: number; - expiresAt?: string; - clickCount: number; - qrCodeUrl?: string; - utmSource?: string; - utmMedium?: string; - utmCampaign?: string; - folderId?: string; - order: number; - createdAt: string; - updatedAt: string; -} - -export interface Tag { - id: string; - name: string; - slug: string; - color?: string; - icon?: string; - visibility: import('@mana/shared-privacy').VisibilityLevel; - usageCount: number; - createdAt: string; - updatedAt: string; -} - -export interface Folder { - id: string; - name: string; - color?: string; - order: number; - createdAt: string; - updatedAt: string; -} - -export interface LinkTag { - id: string; - linkId: string; - tagId: string; -} - -export type StatusFilter = 'all' | 'active' | 'inactive'; - -export interface LinkFilterCriteria { - search?: string; - status?: StatusFilter; - folderId?: string | null; -} - -// ─── Type Converters ─────────────────────────────────────── - -export function toLink(local: LocalLink): Link { - return { - id: local.id, - shortCode: local.shortCode, - customCode: local.customCode ?? undefined, - originalUrl: local.originalUrl, - title: local.title ?? undefined, - description: local.description ?? undefined, - isActive: local.isActive, - password: local.password ?? undefined, - maxClicks: local.maxClicks ?? undefined, - expiresAt: local.expiresAt ?? undefined, - clickCount: local.clickCount, - qrCodeUrl: local.qrCodeUrl ?? undefined, - utmSource: local.utmSource ?? undefined, - utmMedium: local.utmMedium ?? undefined, - utmCampaign: local.utmCampaign ?? undefined, - folderId: local.folderId ?? undefined, - order: local.order, - createdAt: local.createdAt ?? new Date().toISOString(), - updatedAt: deriveUpdatedAt(local), - }; -} - -export function toTag(local: LocalTag): Tag { - return { - id: local.id, - name: local.name, - slug: local.slug, - color: local.color ?? undefined, - icon: local.icon ?? undefined, - visibility: local.visibility ?? 'space', - usageCount: local.usageCount, - createdAt: local.createdAt ?? new Date().toISOString(), - updatedAt: deriveUpdatedAt(local), - }; -} - -export function toFolder(local: LocalFolder): Folder { - return { - id: local.id, - name: local.name, - color: local.color ?? undefined, - order: local.order, - createdAt: local.createdAt ?? new Date().toISOString(), - updatedAt: deriveUpdatedAt(local), - }; -} - -export function toLinkTag(local: LocalLinkTag): LinkTag { - return { - id: local.id, - linkId: local.linkId, - tagId: local.tagId, - }; -} - -// ─── Raw Observable Queries ─────────────────────────────── - -export function allLinks$() { - return liveQuery(async () => { - const locals = await scopedForModule('uload', 'links').toArray(); - const visible = locals.filter((l) => !l.deletedAt); - const decrypted = await decryptRecords('links', visible); - return decrypted.map(toLink); - }); -} - -export function allTags$() { - return liveQuery(async () => { - const locals = await scopedForModule('uload', 'uloadTags').toArray(); - return locals.filter((t) => !t.deletedAt).map(toTag); - }); -} - -export function allFolders$() { - return liveQuery(async () => { - const locals = await scopedForModule('uload', 'uloadFolders').toArray(); - return locals.filter((f) => !f.deletedAt).map(toFolder); - }); -} - -export function allLinkTags$() { - return liveQuery(async () => { - const locals = await scopedForModule('uload', 'linkTags').toArray(); - return locals.filter((lt) => !lt.deletedAt).map(toLinkTag); - }); -} - -// ─── Svelte 5 Reactive Hooks ────────────────────────────── - -export function useAllLinks() { - return useScopedLiveQuery(async () => { - const locals = await scopedForModule('uload', 'links').toArray(); - const visible = locals.filter((l) => !l.deletedAt); - const decrypted = await decryptRecords('links', visible); - return decrypted.map(toLink); - }, [] as Link[]); -} - -export function useAllTags() { - return useScopedLiveQuery(async () => { - const locals = await scopedForModule('uload', 'uloadTags').toArray(); - return locals.filter((t) => !t.deletedAt).map(toTag); - }, [] as Tag[]); -} - -export function useAllFolders() { - return useScopedLiveQuery(async () => { - const locals = await scopedForModule('uload', 'uloadFolders').sortBy( - 'order' - ); - return locals.filter((f) => !f.deletedAt).map(toFolder); - }, [] as Folder[]); -} - -export function useAllLinkTags() { - return useScopedLiveQuery(async () => { - const locals = await scopedForModule('uload', 'linkTags').toArray(); - return locals.filter((lt) => !lt.deletedAt).map(toLinkTag); - }, [] as LinkTag[]); -} - -export function useLinkById(id: string) { - return useScopedLiveQuery( - async () => { - if (!id) return null; - const local = await db.table('links').get(id); - if (!local || local.deletedAt) return null; - const decrypted = await decryptRecord('links', { ...local }); - return toLink(decrypted); - }, - null as Link | null - ); -} - -// ─── Pure Filter / Sort Helpers ─────────────────────────── - -export function getFilteredLinks(links: Link[], filters: LinkFilterCriteria): Link[] { - let result = links; - - if (filters.search) { - const q = filters.search.toLowerCase(); - result = result.filter( - (l) => - l.title?.toLowerCase().includes(q) || - l.originalUrl.toLowerCase().includes(q) || - l.shortCode.toLowerCase().includes(q) - ); - } - if (filters.status === 'active') result = result.filter((l) => l.isActive); - if (filters.status === 'inactive') result = result.filter((l) => !l.isActive); - if (filters.folderId) result = result.filter((l) => l.folderId === filters.folderId); - - return result; -} - -export function getSortedLinks(links: Link[]): Link[] { - return [...links].sort((a, b) => a.order - b.order); -} - -export function getLinkById(links: Link[], id: string): Link | undefined { - return links.find((l) => l.id === id); -} - -export function getTagById(tags: Tag[], id: string): Tag | undefined { - return tags.find((t) => t.id === id); -} - -export function getFolderById(folders: Folder[], id: string): Folder | undefined { - return folders.find((f) => f.id === id); -} - -export function getTagUsageCount(linkTags: LinkTag[], tagId: string): number { - return linkTags.filter((lt) => lt.tagId === tagId).length; -} - -export function getLinkTags(linkTags: LinkTag[], tags: Tag[], linkId: string): Tag[] { - const tagIds = linkTags.filter((lt) => lt.linkId === linkId).map((lt) => lt.tagId); - return tags.filter((t) => tagIds.includes(t.id)); -} - -export function generateShortCode(): string { - const chars = 'abcdefghijklmnopqrstuvwxyz0123456789'; - let code = ''; - for (let i = 0; i < 6; i++) { - code += chars[Math.floor(Math.random() * chars.length)]; - } - return code; -} - -export function slugify(name: string): string { - return name - .toLowerCase() - .replace(/[^a-z0-9]+/g, '-') - .replace(/^-+|-+$/g, ''); -} diff --git a/apps/mana/apps/web/src/lib/modules/uload/types.ts b/apps/mana/apps/web/src/lib/modules/uload/types.ts deleted file mode 100644 index 70dbcd1fe..000000000 --- a/apps/mana/apps/web/src/lib/modules/uload/types.ts +++ /dev/null @@ -1,46 +0,0 @@ -/** - * uLoad module types for the unified app. - */ - -import type { BaseRecord } from '@mana/local-store'; -import type { VisibilityLevel } from '@mana/shared-privacy'; - -export interface LocalLink extends BaseRecord { - shortCode: string; - customCode?: string | null; - originalUrl: string; - title?: string | null; - description?: string | null; - isActive: boolean; - password?: string | null; - maxClicks?: number | null; - expiresAt?: string | null; - clickCount: number; - qrCodeUrl?: string | null; - utmSource?: string | null; - utmMedium?: string | null; - utmCampaign?: string | null; - folderId?: string | null; - order: number; - source?: string | null; -} - -export interface LocalTag extends BaseRecord { - name: string; - slug: string; - color?: string | null; - icon?: string | null; - visibility?: VisibilityLevel; - usageCount: number; -} - -export interface LocalFolder extends BaseRecord { - name: string; - color?: string | null; - order: number; -} - -export interface LocalLinkTag extends BaseRecord { - linkId: string; - tagId: string; -} diff --git a/apps/mana/apps/web/src/lib/modules/uload/views/DetailView.svelte b/apps/mana/apps/web/src/lib/modules/uload/views/DetailView.svelte deleted file mode 100644 index 373208dde..000000000 --- a/apps/mana/apps/web/src/lib/modules/uload/views/DetailView.svelte +++ /dev/null @@ -1,178 +0,0 @@ - - - - - detail.deleteWithUndo({ - label: $_('uload.detail_view.deleted_toast'), - delete: deleteLink, - goBack, - })} -> - {#snippet body(link)} - - -
-
- {$_('uload.detail_view.label_url')} - -
- -
- {$_('uload.detail_view.label_short_code')} - -
- - {#if link.shortCode} -
- {$_('uload.detail_view.label_short_code_legacy')} - {link.shortCode} -
- {/if} - -
- {$_('uload.detail_view.label_active')} - -
- -
- {$_('uload.detail_view.label_clicks')} - {link.clickCount} -
- -
- {$_('uload.detail_view.label_expires_at')} - -
-
- -
- - -
- -
- {$_('uload.detail_view.meta_created', { - values: { date: formatDate(new Date(link.createdAt ?? '')) }, - })} - {#if link.updatedAt} - {$_('uload.detail_view.meta_updated', { - values: { date: formatDate(new Date(link.updatedAt)) }, - })} - {/if} -
- {/snippet} -
diff --git a/apps/mana/apps/web/src/lib/splitscreen/registry.ts b/apps/mana/apps/web/src/lib/splitscreen/registry.ts index 02b17640e..f5197b15e 100644 --- a/apps/mana/apps/web/src/lib/splitscreen/registry.ts +++ b/apps/mana/apps/web/src/lib/splitscreen/registry.ts @@ -22,7 +22,6 @@ const SPLIT_APP_ID_LIST = [ 'skilltree', 'times', 'questions', - 'uload', 'calc', 'places', 'automations', diff --git a/apps/mana/apps/web/src/routes/(app)/uload/+page.svelte b/apps/mana/apps/web/src/routes/(app)/uload/+page.svelte deleted file mode 100644 index b088d74b0..000000000 --- a/apps/mana/apps/web/src/routes/(app)/uload/+page.svelte +++ /dev/null @@ -1,804 +0,0 @@ - - - - {$_('uload.page.title')} - - - -
-
- -
-
-

uLoad

-

- {folders.length > 0 - ? $_('uload.page.counts', { - values: { links: filteredLinks.length, folders: folders.length }, - }) - : $_('uload.page.counts_no_folders', { - values: { links: filteredLinks.length }, - })} -

-
-
- - {$_('uload.page.all_links')} - - -
-
- - - {#if showCreateForm} -
-
-
- - e.key === 'Enter' && createLink()} - /> -
-
- - -
-
- - -
-
- - - - {#if showAdvanced} -
-
- - -
-
- - -
-
- - -
-
- {/if} - - - - {#if showUtm} -
-
- - -
-
- - -
-
- - -
-
- {/if} - -
- -
-
- {/if} - - -
-
- - -
- - {#if folders.length > 0} - - {/if} -
- - - {#if allLinks.loading} -
- {#each Array(3) as _} -
- {/each} -
- {:else if filteredLinks.length === 0} -
- -

{$_('uload.page.empty_title')}

-

{$_('uload.page.empty_desc')}

- -
- {:else} -
- {#each filteredLinks as link (link.id)} -
-
-
-
- -

{link.title || link.shortCode}

- - /{link.shortCode} - - {#if link.utmSource || link.utmMedium || link.utmCampaign} - {$_('uload.page.badge_utm')} - {/if} - {#if link.password} - {$_('uload.page.badge_password')} - {/if} - {#if link.expiresAt} - {$_('uload.page.badge_expires')} - {/if} -
-

{link.originalUrl}

- {#if getLinkTags(linkTags, tags, link.id).length > 0} -
- {#each getLinkTags(linkTags, tags, link.id) as tag} - - {tag.name} - - {/each} -
- {/if} -
- -
- - - {link.clickCount} - - - - - - -
-
-
- {/each} -
- {/if} -
-
-
- - -{#if editingLink} -
(editingLink = null)} - onkeydown={(e) => e.key === 'Escape' && (editingLink = null)} - tabindex="-1" - role="presentation" - > -
e.stopPropagation()} - role="none" - > -
-

{$_('uload.page.modal_edit_title')}

- -
- -
-
- - -
-
- - -
-
- -
- /{editingLink.shortCode} - {$_('uload.page.short_code_locked')} -
-
- -
-

{$_('uload.page.section_utm')}

-
- - - -
-
- -
-

{$_('uload.page.section_advanced')}

-
-
- - -
-
- - -
-
- - -
-
-
-
- -
- - -
-
-
-{/if} - - -{#if qrLink} -
(qrLink = null)} - onkeydown={(e) => e.key === 'Escape' && (qrLink = null)} - tabindex="-1" - role="presentation" - > -
e.stopPropagation()} - role="none" - > -
-

{$_('uload.page.modal_qr_title')}

- -
- -
-
- {$_('uload.page.qr_alt', -
-

{getShortUrl(qrLink.shortCode)}

-
- - -
-
-
-
-{/if} diff --git a/apps/mana/apps/web/src/routes/(app)/uload/analytics/[id]/+page.svelte b/apps/mana/apps/web/src/routes/(app)/uload/analytics/[id]/+page.svelte deleted file mode 100644 index 5df24cf41..000000000 --- a/apps/mana/apps/web/src/routes/(app)/uload/analytics/[id]/+page.svelte +++ /dev/null @@ -1,393 +0,0 @@ - - - - {$_('uload.analytics_route.title')} - - - -
- -
- - - -
-

{$_('uload.analytics_route.heading')}

- {#if link} -

- /{link.shortCode} - → {link.originalUrl} -

- {/if} -
-
- - {#if loading} -
- {#each Array(4) as _} -
- {/each} -
- {:else if !link} -
-

{$_('uload.analytics_route.not_found')}

-
- {:else} - -
-
-

- {$_('uload.analytics_route.stat_clicks')} -

-

- {stats?.totalClicks ?? link.clickCount} -

-
-
-

- {$_('uload.analytics_route.stat_unique')} -

-

- {stats?.uniqueVisitors ?? '-'} -

-
-
-

- {$_('uload.analytics_route.stat_status')} -

-

- {#if link.isActive} - {$_('uload.analytics_route.status_active')} - {:else} - {$_('uload.analytics_route.status_inactive')} - {/if} -

-
-
-

- {$_('uload.analytics_route.stat_created')} -

-

- {formatDate(new Date(link.createdAt))} -

-
-
- - -
-

- {$_('uload.analytics_route.section_details')} -

-
-
- {$_('uload.analytics_route.label_target_url')} - - {link.originalUrl} - -
- {#if link.title} -
- {$_('uload.analytics_route.label_title')} - {link.title} -
- {/if} - {#if link.utmSource || link.utmMedium || link.utmCampaign} -
-

- {$_('uload.analytics_route.label_utm_params')} -

-
- {#if link.utmSource} -
- {$_('uload.analytics_route.utm_source')} - {link.utmSource} -
- {/if} - {#if link.utmMedium} -
- {$_('uload.analytics_route.utm_medium')} - {link.utmMedium} -
- {/if} - {#if link.utmCampaign} -
- {$_('uload.analytics_route.utm_campaign')} - {link.utmCampaign} -
- {/if} -
-
- {/if} - {#if link.expiresAt} -
- {$_('uload.analytics_route.label_expires_at')} - {formatDate(new Date(link.expiresAt))} -
- {/if} - {#if link.maxClicks} -
- {$_('uload.analytics_route.label_max_clicks')} - {$_('uload.analytics_route.max_clicks_value', { - values: { used: link.clickCount, max: link.maxClicks }, - })} -
- {/if} - {#if link.password} -
- {$_('uload.analytics_route.label_password_protected')} - {$_('uload.analytics_route.yes')} -
- {/if} -
-
- - -
-
-

- {$_('uload.analytics_route.section_timeline')} -

-
- {#each [7, 30, 90] as d} - - {/each} -
-
- {#if timeline.length > 0} -
- {#each timeline as day} -
-
- -
- {/each} -
-
- {timeline[0]?.date} - {timeline[timeline.length - 1]?.date} -
- {:else if !serverAvailable} -
-

- {$_('uload.analytics_route.hint_no_server')} -

-

- {$_('uload.analytics_route.hint_local_count', { - values: { count: link.clickCount }, - })} -

-
- {:else} -

- {$_('uload.analytics_route.empty_period')} -

- {/if} -
- - - {#if serverAvailable} -
- -
-

- {$_('uload.analytics_route.section_devices')} -

- {#if devices.length > 0} -
- {#each devices as d} -
-
- {d.deviceType || $_('uload.analytics_route.unknown')} - - {Math.round((d.count / totalDevices) * 100)}% - -
-
-
-
-
- {/each} -
- {:else} -

- {$_('uload.analytics_route.empty_no_data')} -

- {/if} -
- - -
-

- {$_('uload.analytics_route.section_referrers')} -

- {#if referrers.length > 0} -
- {#each referrers.slice(0, 8) as r} -
- - {r.referer || $_('uload.analytics_route.direct')} - - {r.count} -
- {/each} -
- {:else} -

- {$_('uload.analytics_route.empty_no_data')} -

- {/if} -
- - -
-

- {$_('uload.analytics_route.section_countries')} -

- {#if countries.length > 0} -
- {#each countries.slice(0, 8) as c} -
-
- {c.country || $_('uload.analytics_route.unknown')} - - {Math.round((c.count / totalCountries) * 100)}% - -
-
-
-
-
- {/each} -
- {:else} -

- {$_('uload.analytics_route.empty_no_data')} -

- {/if} -
-
- {/if} - {/if} -
-
diff --git a/apps/mana/apps/web/src/routes/(app)/uload/links/+page.svelte b/apps/mana/apps/web/src/routes/(app)/uload/links/+page.svelte deleted file mode 100644 index 7c85301ed..000000000 --- a/apps/mana/apps/web/src/routes/(app)/uload/links/+page.svelte +++ /dev/null @@ -1,353 +0,0 @@ - - - - {$_('uload.links_route.title')} - - - -
-
- -
-
- - - -
-

- {$_('uload.links_route.heading')} - {#if filteredLinks.length > 0} - ({filteredLinks.length}) - {/if} -

-
-
-
- -
-
- - -
-
- - -
- - {#if folders.length > 0} - - {/if} -
- - - {#if selectMode && selectedIds.size > 0} -
- -
- - -
- {/if} - - - {#if allLinks.loading} -
- {#each Array(5) as _} -
- {/each} -
- {:else if filteredLinks.length === 0} -
- -

{$_('uload.links_route.empty_title')}

- {#if searchQuery || selectedStatus !== 'all' || selectedFolderId} -

{$_('uload.links_route.empty_filtered')}

- {:else} -

{$_('uload.links_route.empty_root')}

- {/if} -
- {:else} -
- {#each filteredLinks as link (link.id)} -
-
- {#if selectMode} - toggleSelect(link.id)} - class="mr-3 h-4 w-4 shrink-0 rounded" - /> - {/if} -
-
- -

{link.title || link.shortCode}

- - /{link.shortCode} - - {#if link.utmSource || link.utmMedium || link.utmCampaign} - UTM - {/if} -
-

{link.originalUrl}

- {#if getLinkTags(linkTags, tags, link.id).length > 0} -
- {#each getLinkTags(linkTags, tags, link.id) as tag} - - {tag.name} - - {/each} -
- {/if} -
- -
- - - {link.clickCount} - - - - -
-
-
- {/each} -
- {/if} -
-
-
diff --git a/apps/mana/apps/web/src/routes/(app)/uload/settings/+page.svelte b/apps/mana/apps/web/src/routes/(app)/uload/settings/+page.svelte deleted file mode 100644 index afeed4107..000000000 --- a/apps/mana/apps/web/src/routes/(app)/uload/settings/+page.svelte +++ /dev/null @@ -1,206 +0,0 @@ - - - - - {$_('uload.settings_route.title')} - - - -
-
-
- {$_('uload.settings_route.heading')} - {$_('uload.settings_route.subtitle')} -
-
- -
-

{$_('uload.settings_route.section_data')}

-
-
-

{links.value?.length ?? 0}

-

{$_('uload.settings_route.stat_links')}

-
-
-

{tags.value?.length ?? 0}

-

{$_('uload.settings_route.stat_tags')}

-
-
-

{folders.value?.length ?? 0}

-

{$_('uload.settings_route.stat_folders')}

-
-
-
- -
-

{$_('uload.settings_route.section_export')}

-

{$_('uload.settings_route.export_hint')}

- -
- -
-

{$_('uload.settings_route.section_danger')}

-

- {$_('uload.settings_route.danger_hint')} -

- -
-
-
- - diff --git a/apps/mana/apps/web/src/routes/(app)/uload/tags/+page.svelte b/apps/mana/apps/web/src/routes/(app)/uload/tags/+page.svelte deleted file mode 100644 index db82fbde4..000000000 --- a/apps/mana/apps/web/src/routes/(app)/uload/tags/+page.svelte +++ /dev/null @@ -1,182 +0,0 @@ - - - -
-
-
- - - -

{$_('uload.tags_route.heading')}

-
- -
- - {#if showCreateForm} -
-
-
- - e.key === 'Enter' && createTag()} - /> -
-
- - -
- -
-
- {/if} - - {#if !tags.value || tags.value.length === 0} -
-

- {$_('uload.tags_route.empty_title')} -

-

- {$_('uload.tags_route.empty_desc')} -

-
- {:else} -
- {#each tags.value as tag (tag.id)} -
- {#if editingTag?.id === tag.id} -
- -
- - - -
-
- {:else} -
-
- - {tag.name} -
-
- {$_('uload.tags_route.links_count', { - values: { count: getUsageCount(tag.id) }, - })} - - -
-
- {/if} -
- {/each} -
- {/if} -
-
diff --git a/apps/mana/apps/web/src/routes/status/+page.server.ts b/apps/mana/apps/web/src/routes/status/+page.server.ts index 961c0ff52..5c6669816 100644 --- a/apps/mana/apps/web/src/routes/status/+page.server.ts +++ b/apps/mana/apps/web/src/routes/status/+page.server.ts @@ -15,7 +15,6 @@ interface ServiceStatus { const SERVICES = [ { name: 'Auth', url: process.env.PUBLIC_MANA_AUTH_URL || 'http://localhost:3001' }, { name: 'Sync', url: process.env.PUBLIC_SYNC_SERVER_URL || 'http://localhost:3010' }, - { name: 'Uload Server', url: process.env.PUBLIC_ULOAD_SERVER_URL || 'http://localhost:3070' }, { name: 'Media', url: process.env.PUBLIC_MANA_MEDIA_URL || 'http://localhost:3011' }, { name: 'LLM', url: process.env.PUBLIC_MANA_LLM_URL || 'http://localhost:3025' }, { name: 'Geocoding', url: process.env.PUBLIC_MANA_GEOCODING_URL || 'http://localhost:3018' }, diff --git a/apps/uload/CLAUDE.md b/apps/uload/CLAUDE.md deleted file mode 100644 index f53fa899d..000000000 --- a/apps/uload/CLAUDE.md +++ /dev/null @@ -1,128 +0,0 @@ -# uLoad — URL Shortener & Link Management - -**Live:** https://ulo.ad - -## Architecture - -uLoad uses a **local-first** architecture with a lightweight Hono/Bun server for redirects and analytics. - -``` -Browser → IndexedDB (Links, Tags, Folders) - ↕ sync - mana-sync → PostgreSQL - -Browser → /r/:code → Hono Server → PostgreSQL (redirect + click tracking) -``` - -## Project Structure - -``` -apps/uload/ -├── apps/ -│ ├── web/ # SvelteKit web app (local-first) -│ ├── server/ # Hono/Bun redirect & analytics server -│ └── landing/ # Astro marketing page -├── packages/ -│ └── uload-database/ # Shared Drizzle schema -└── package.json -``` - -## Tech Stack - -| Layer | Technology | -|-------|-----------| -| **Web** | SvelteKit 2, Svelte 5 (runes), Tailwind CSS 4 | -| **Server** | Hono + Bun | -| **Data** | Local-first (Dexie.js + mana-sync) | -| **Database** | PostgreSQL via Drizzle ORM | -| **Auth** | mana-auth (Better Auth + EdDSA JWT) | -| **Landing** | Astro 5 | -| **PWA** | @vite-pwa/sveltekit | -| **i18n** | svelte-i18n (DE/EN) | - -## Commands - -```bash -# Development -pnpm dev:uload:web # SvelteKit dev server -pnpm dev:uload:server # Hono/Bun server (port 3070) -pnpm dev:uload:landing # Landing page -pnpm dev:uload:local # Web + Sync + Server (no auth) -pnpm dev:uload:full # Everything incl. auth - -# Build & Deploy -pnpm --filter @uload/web build -pnpm --filter @uload/landing build -pnpm deploy:landing:uload # Deploy landing to Cloudflare Pages - -# Type Check -pnpm --filter @uload/web check -pnpm --filter @uload/server type-check -pnpm --filter @mana/uload-database type-check -``` - -## Ports - -| Service | Dev Port | Prod Port | -|---------|----------|-----------| -| Web | 5173 | 5029 | -| Server | 3070 | 3041 | -| Landing | 4321 | Cloudflare Pages | - -## Hono Server Routes - -| Route | Auth | Description | -|-------|------|-------------| -| `GET /health` | No | Health check | -| `GET /r/:code` | No | Redirect + click tracking | -| `GET /public/u/:username` | No | Public user profile + links | -| `GET /api/v1/analytics/:linkId` | JWT | Click stats | -| `GET /api/v1/analytics/:linkId/timeline` | JWT | Clicks over time | -| `GET /api/v1/analytics/:linkId/devices` | JWT | Device breakdown | -| `GET /api/v1/analytics/:linkId/referrers` | JWT | Top referrers | -| `GET /api/v1/analytics/:linkId/countries` | JWT | Country breakdown | -| `POST /api/v1/stripe/checkout` | JWT | Stripe session (stub) | -| `POST /api/v1/stripe/webhook` | No | Stripe webhook (stub) | -| `POST /api/v1/email/send-invitation` | JWT | Team invite (stub) | - -## Local-First Collections - -| Collection | Fields | -|-----------|--------| -| `links` | shortCode, originalUrl, title, isActive, clickCount, utmSource/Medium/Campaign, folderId | -| `tags` | name, slug, color, icon, isPublic, usageCount | -| `folders` | name, color, order | -| `linkTags` | linkId, tagId | - -## Web App Pages - -| Route | Description | -|-------|-------------| -| `/my/links` | Link management (CRUD, QR, UTM, bulk) | -| `/my/tags` | Tag management | -| `/my/analytics/[id]` | Per-link analytics dashboard | -| `/settings` | Account & data settings | -| `/pricing` | Subscription plans (static) | -| `/u/[username]` | Public user profile | -| `/login` | Login (shared-auth-ui) | -| `/register` | Register (shared-auth-ui) | - -## Docker - -```bash -# Build -./scripts/mac-mini/build-app.sh uload-web -./scripts/mac-mini/build-app.sh uload-server - -# Services in docker-compose.macmini.yml: -# - uload-server (port 3041, Bun) -# - uload-web (port 5029, Node) -``` - -## Key Patterns - -- **Svelte 5 Runes**: Use `$state`, `$derived`, `$effect` — never `$:` -- **Local-first**: All CRUD via `linkCollection.insert/update/delete` (IndexedDB) -- **Analytics**: Fetched from Hono server, not local (server-only click data) -- **Auth**: `authStore` from `@mana/shared-auth-ui`, `AuthGate` with guest mode -- **Sync**: Starts on login via `uloadStore.startSync()`, stops on logout diff --git a/apps/uload/README.md b/apps/uload/README.md deleted file mode 100644 index bde7ba971..000000000 --- a/apps/uload/README.md +++ /dev/null @@ -1,151 +0,0 @@ -# uLoad - URL Shortener & Link Management - -A modern URL shortener and link management platform built with SvelteKit and PocketBase. - -## 🚀 Production - -**Live:** https://ulo.ad -**Admin:** https://ulo.ad/_/ - -## 🛠 Tech Stack - -- **Frontend:** SvelteKit 2.0 + Svelte 5 -- **Backend:** PocketBase (embedded) -- **Styling:** Tailwind CSS 4.0 -- **Deployment:** Docker + Coolify on Hetzner VPS -- **Database:** SQLite (via PocketBase) - -## 📦 Features - -- URL shortening with custom codes -- QR code generation -- Click analytics -- User profiles (e.g., ulo.ad/p/username) -- Link management dashboard -- Real-time statistics - -## 🏃 Development - -```bash -# Install dependencies -npm install --legacy-peer-deps - -# Start development server -npm run dev - -# Start with PocketBase backend -npm run dev:all - -# Run tests -npm run test - -# Type checking -npm run check -``` - -## 🐳 Docker Deployment - -```bash -# Build and run locally -docker-compose up --build - -# Access at: -# Frontend: http://localhost:3000 -# PocketBase: http://localhost:8090 -``` - -## 📝 Documentation - -- [Deployment Guide](./DEPLOYMENT.md) - Complete Docker Compose deployment instructions -- [Lessons Learned](./DEPLOYMENT_LESSONS_LEARNED.md) - Troubleshooting and insights -- [Domain Setup](./DOMAIN_SETUP_ULO_AD.md) - ulo.ad configuration -- [Coolify Setup](./COOLIFY_SETUP.md) - Detailed Coolify configuration - -## 🔧 Environment Variables - -```bash -NODE_ENV=production -PORT=3000 -ORIGIN=https://ulo.ad -PUBLIC_POCKETBASE_URL=https://ulo.ad/api -POCKETBASE_ADMIN_EMAIL=admin@example.com -POCKETBASE_ADMIN_PASSWORD=secure_password -``` - -See `.env.example` for all configuration options. - -## 📂 Project Structure - -``` -uload/ -├── src/ # SvelteKit application -│ ├── routes/ # Pages and API routes -│ ├── lib/ # Components and utilities -│ └── app.html # HTML template -├── backend/ # PocketBase configuration -│ ├── pb_schema.json # Database schema -│ └── init-pocketbase.sh # Setup script -├── build/ # Production build output -├── static/ # Static assets -├── Dockerfile # Multi-stage Docker build -├── docker-compose.yml # Local development -├── supervisord.conf # Process management -└── CLAUDE.md # AI assistant context -``` - -## 🚢 Deployment - -The application is deployed on Hetzner VPS using Coolify with automatic deployments on push to main branch. - -```bash -# Commit and push to deploy -git add . -git commit -m "Update" -git push origin main -# Coolify automatically deploys -``` - -### Manual Deployment Steps: - -1. Set DNS A record to `91.99.221.179` -2. Add domain in Coolify -3. Update environment variables -4. Enable SSL certificate -5. Deploy application - -## 📊 Monitoring - -- **Health Check:** https://ulo.ad/health -- **Admin Panel:** https://ulo.ad/_/ -- **Server:** Hetzner CX21 (2 vCPU, 4GB RAM) -- **Uptime:** 99.9% SLA - -## 🔐 Security - -- HTTPS enforced -- Environment-based configuration -- Secure admin authentication -- Rate limiting on API endpoints -- Regular security updates - -## 🤝 Contributing - -1. Fork the repository -2. Create your feature branch (`git checkout -b feature/amazing-feature`) -3. Commit your changes (`git commit -m 'Add amazing feature'`) -4. Push to the branch (`git push origin feature/amazing-feature`) -5. Open a Pull Request - -## 🐛 Troubleshooting - -Common issues and solutions are documented in [DEPLOYMENT_LESSONS_LEARNED.md](./DEPLOYMENT_LESSONS_LEARNED.md) - -For support, check: - -- Application logs in Coolify -- Health endpoint status -- PocketBase admin panel - -## 📄 License - -Private - Memoro AI © 2024 diff --git a/apps/uload/apps/landing/astro.config.mjs b/apps/uload/apps/landing/astro.config.mjs deleted file mode 100644 index 5721576c6..000000000 --- a/apps/uload/apps/landing/astro.config.mjs +++ /dev/null @@ -1,16 +0,0 @@ -import { defineConfig } from 'astro/config'; -import tailwind from '@astrojs/tailwind'; -import mdx from '@astrojs/mdx'; -import sitemap from '@astrojs/sitemap'; - -export default defineConfig({ - site: 'https://ulo.ad', - integrations: [tailwind(), mdx(), sitemap()], - i18n: { - defaultLocale: 'de', - locales: ['de', 'en'], - routing: { - prefixDefaultLocale: false, - }, - }, -}); diff --git a/apps/uload/apps/landing/package.json b/apps/uload/apps/landing/package.json deleted file mode 100644 index ecb2e1860..000000000 --- a/apps/uload/apps/landing/package.json +++ /dev/null @@ -1,25 +0,0 @@ -{ - "name": "@uload/landing", - "type": "module", - "version": "1.0.0", - "scripts": { - "dev": "astro dev", - "build": "astro build", - "preview": "astro preview", - "astro": "astro", - "check": "astro check" - }, - "dependencies": { - "@astrojs/check": "^0.9.4", - "@astrojs/mdx": "^4.0.8", - "@astrojs/sitemap": "^3.2.1", - "@astrojs/tailwind": "^6.0.2", - "@mana/shared-landing-ui": "workspace:*", - "astro": "^5.1.1", - "tailwindcss": "^3.4.17" - }, - "devDependencies": { - "@types/node": "^22.10.2", - "typescript": "^5.7.2" - } -} diff --git a/apps/uload/apps/landing/src/components/Footer.astro b/apps/uload/apps/landing/src/components/Footer.astro deleted file mode 100644 index adbcb23be..000000000 --- a/apps/uload/apps/landing/src/components/Footer.astro +++ /dev/null @@ -1,114 +0,0 @@ ---- -const currentYear = new Date().getFullYear(); - -const footerLinks = { - produkt: [ - { href: '/features', label: 'Features' }, - { href: '/#pricing', label: 'Preise' }, - { href: '/blog', label: 'Blog' }, - ], - unternehmen: [{ href: '/about', label: 'Über uns' }], - rechtliches: [ - { href: '/datenschutz', label: 'Datenschutz' }, - { href: '/impressum', label: 'Impressum' }, - { href: '/agb', label: 'AGB' }, - { href: '/sicherheit', label: 'Sicherheit' }, - ], -}; - -const appUrl = 'https://app.ulo.ad'; ---- - -
-
-
- -
- -
- u -
- uLoad -
-

- Der intelligente URL-Shortener für Profis. Verkürzen Sie Links, erstellen Sie QR-Codes und - analysieren Sie Klicks. -

-
- - -
-

Produkt

- -
- - -
-

Unternehmen

- -
- - -
-

Rechtliches

- -
-
- - -
-

- © {currentYear} uLoad. Alle Rechte vorbehalten. -

- -
-
-
diff --git a/apps/uload/apps/landing/src/components/HeroSection.astro b/apps/uload/apps/landing/src/components/HeroSection.astro deleted file mode 100644 index b57d1ad8e..000000000 --- a/apps/uload/apps/landing/src/components/HeroSection.astro +++ /dev/null @@ -1,195 +0,0 @@ ---- -const appUrl = 'https://app.ulo.ad'; ---- - -
- -
-
-
-
-
-
- -
-
- -
- - - - - DSGVO-konform - - - - - - Blitzschnell - - - - - - 100% Sicher - -
- - -

- More than links. - - Your digital identity. - -

- -

- Der einzige Link-Shortener mit integriertem Profile-Builder. Erstelle kurze Links, - beeindruckende Profilkarten und manage alles im Team. -

- - - - - -
- -

- Keine Anmeldung erforderlich • Kostenlos • QR-Code inklusive -

-
-
- - -
- -
-
- - - -
-

Smart Links

-

Kurze URLs mit Tracking, Ablaufdatum und Passwortschutz

- - Mehr erfahren → - -
- - -
-
- - - -
-

Profile Cards

-

Beeindruckende Profilseiten mit Drag & Drop Builder

- - Templates ansehen → - -
- - -
-
- - - -
-

Team Workspace

-

Gemeinsam Links verwalten mit granularen Berechtigungen

- - Für Teams → - -
-
-
-
diff --git a/apps/uload/apps/landing/src/components/Navigation.astro b/apps/uload/apps/landing/src/components/Navigation.astro deleted file mode 100644 index 7fb1f5f16..000000000 --- a/apps/uload/apps/landing/src/components/Navigation.astro +++ /dev/null @@ -1,86 +0,0 @@ ---- -const navLinks = [ - { href: '/features', label: 'Features' }, - { href: '/blog', label: 'Blog' }, - { href: '/about', label: 'Über uns' }, -]; - -const appUrl = 'https://app.ulo.ad'; ---- - -
- -
- - diff --git a/apps/uload/apps/landing/src/content/blog/link-tracking-guide.md b/apps/uload/apps/landing/src/content/blog/link-tracking-guide.md deleted file mode 100644 index a4134ca62..000000000 --- a/apps/uload/apps/landing/src/content/blog/link-tracking-guide.md +++ /dev/null @@ -1,92 +0,0 @@ ---- -title: Der ultimative Link-Tracking Guide für 2024 -description: Erfahren Sie, wie Sie mit modernem Link-Tracking Ihre Marketing-Performance messbar verbessern und dabei DSGVO-konform bleiben. -pubDate: 2024-01-20 -author: Till Schneider -tags: [tracking, analytics, dsgvo, marketing] ---- - -Link-Tracking ist der Schlüssel zu datengetriebenem Marketing. In diesem umfassenden Guide zeigen wir Ihnen, wie Sie Ihre Links professionell tracken, dabei datenschutzkonform bleiben und Ihre Conversion-Rate signifikant steigern. - -## Was ist Link-Tracking? - -Link-Tracking ermöglicht es Ihnen, das Verhalten Ihrer Nutzer zu verstehen: - -- Woher kommen Ihre Besucher? -- Welche Kampagnen funktionieren? -- Wie hoch ist Ihre Conversion-Rate? -- Welche Inhalte performen am besten? - -## Die wichtigsten Metriken - -### 1. Click-Through-Rate (CTR) - -Die CTR zeigt, wie viele Personen Ihren Link gesehen und geklickt haben. Eine gute CTR liegt je nach Kanal zwischen 2-5%. - -### 2. Conversion Rate - -Der Prozentsatz der Klicks, die zu einer gewünschten Aktion führen. - -### 3. Bounce Rate - -Wie viele Nutzer verlassen Ihre Seite sofort wieder? - -### 4. Geographic Distribution - -Verstehen Sie, aus welchen Ländern und Regionen Ihre Besucher kommen. - -## UTM-Parameter richtig einsetzen - -UTM-Parameter sind der Standard für Campaign-Tracking: - -``` -https://ulo.ad/angebot -?utm_source=newsletter -&utm_medium=email -&utm_campaign=winter-sale -``` - -### Die 5 UTM-Parameter - -1. **utm_source**: Woher kommt der Traffic? -2. **utm_medium**: Welches Medium? -3. **utm_campaign**: Welche Kampagne? -4. **utm_content**: Welcher spezifische Link? -5. **utm_term**: Welches Keyword? - -## DSGVO-konformes Tracking - -### Was ist erlaubt? - -✅ **Anonymisierte Daten** - -- Gerätetyp -- Browser -- Ungefährer Standort -- Referrer - -### Was braucht Zustimmung? - -❌ **Personenbezogene Daten** - -- Vollständige IP-Adressen -- Device Fingerprinting -- Cross-Site Tracking - -## Best Practices für Link-Tracking - -### 1. Konsistente Namenskonvention - -Entwickeln Sie ein einheitliches Schema für Ihre Kampagnen. - -### 2. Dokumentation führen - -Erstellen Sie eine Tracking-Tabelle für alle Kampagnen. - -### 3. Regelmäßige Bereinigung - -Löschen Sie alte, inaktive Links regelmäßig. - -## Fazit - -Professionelles Link-Tracking ist kein Nice-to-have, sondern ein Must-have für erfolgreiches digitales Marketing. Mit den richtigen Tools und Prozessen können Sie Ihre Marketing-Performance signifikant steigern. diff --git a/apps/uload/apps/landing/src/content/blog/psychologie-kurzer-urls.md b/apps/uload/apps/landing/src/content/blog/psychologie-kurzer-urls.md deleted file mode 100644 index e05de2c8d..000000000 --- a/apps/uload/apps/landing/src/content/blog/psychologie-kurzer-urls.md +++ /dev/null @@ -1,76 +0,0 @@ ---- -title: Die Psychologie kurzer URLs - Warum unser Gehirn sie liebt -description: 42% weniger Klicks bei langen URLs – diese erstaunliche Zahl zeigt, wie stark die Länge eines Links unsere Entscheidung beeinflusst. Erfahren Sie die Wissenschaft dahinter. -pubDate: 2024-01-15 -author: Till Schneider -tags: [urls, psychology, conversion, marketing] ---- - -**42% weniger Klicks bei langen URLs** – diese erstaunliche Zahl zeigt, wie stark die Länge eines Links unsere Entscheidung beeinflusst, darauf zu klicken oder nicht. In diesem umfassenden Artikel tauchen wir tief in die Psychologie hinter kurzen URLs ein und zeigen Ihnen, wie Sie dieses Wissen für Ihren digitalen Erfolg nutzen können. - -## Das Problem mit langen URLs: Wenn Links Misstrauen erzeugen - -Stellen Sie sich vor: Fast die Hälfte Ihrer potenziellen Besucher klickt nicht auf Ihren Link – nur weil er zu lang ist. Was auf den ersten Blick wie eine technische Kleinigkeit erscheint, ist in Wahrheit ein psychologisches Phänomen mit enormen Auswirkungen auf Ihre Online-Performance. - -### Die Spam-Alarm-Reaktion unseres Gehirns - -Aktuelle Studien zeigen eindeutig: URLs, die länger als 100 Zeichen sind, lösen automatisch Misstrauen aus. Unser Gehirn hat über Jahre hinweg gelernt, dass lange, unleserliche Links mit unzähligen Parametern oft zu zweifelhaften Inhalten führen. - -Vergleichen Sie diese beiden URLs: - -**Lange URL (schlecht):** - -``` -https://example.com/product?id=12345&utm_source=newsletter&utm_medium=email&utm_campaign=summer2024 -``` - -**Kurze URL (gut):** - -``` -https://ulo.ad/summer-sale -``` - -### Mobile Nutzer: Die vergessene Mehrheit - -In einer Welt, in der über 60% des Web-Traffics von mobilen Geräten kommt, sind lange URLs ein noch größeres Problem. Mobile Nutzer scrollen definitiv nicht horizontal, um einen Link vollständig zu sehen. - -## Die Wissenschaft dahinter: Cognitive Load Theory - -Die Cognitive Load Theory erklärt, warum kurze URLs so effektiv sind. Unser Gehirn ist darauf programmiert, Energie zu sparen. Bei der Verarbeitung von Informationen sucht es immer nach dem Weg des geringsten Widerstands. - -## Die vier Säulen des Link-Vertrauens - -1. **Erkennbare Domain (60% Wichtigkeit)** - Menschen wollen wissen, wo sie landen werden -2. **Keine kryptischen Zeichen (25% Wichtigkeit)** - Zufällige Zahlen-Buchstaben-Kombinationen schrecken ab -3. **Optimale Länge (10% Wichtigkeit)** - Die magische Grenze liegt bei etwa 50 Zeichen -4. **HTTPS-Verschlüsselung (5% Wichtigkeit)** - Ein Hygienefaktor - -## Praktische Optimierungsstrategien - -### 1. Sprechende URLs verwenden - -❌ **Schlecht:** `ulo.ad/p47829` -✅ **Gut:** `ulo.ad/sommer-sale` - -### 2. Die 50-Zeichen-Regel - -Halten Sie Ihre URLs unter 50 Zeichen. Das ist: - -- Kurz genug für Twitter/X -- Lesbar auf Mobilgeräten -- Merkbar für Nutzer - -### 3. A/B-Testing ist Ihr Freund - -Testen Sie verschiedene URL-Varianten und messen Sie die Performance. - -## Fazit: Die Macht der Kürze - -Die Psychologie kurzer URLs ist keine Raketenwissenschaft, aber ihre Auswirkungen sind enorm. In einer Welt, in der Aufmerksamkeit die wertvollste Währung ist, können kurze, vertrauenswürdige Links den Unterschied zwischen Erfolg und Misserfolg ausmachen. - -### Die wichtigsten Takeaways - -1. **42% weniger Klicks** bei URLs über 100 Zeichen -2. **Cognitive Load Theory**: Unser Gehirn liebt Einfachheit -3. **50 Zeichen** ist die magische Grenze -4. **Sprechende URLs** performen 39% besser diff --git a/apps/uload/apps/landing/src/content/config.ts b/apps/uload/apps/landing/src/content/config.ts deleted file mode 100644 index 858ec45ce..000000000 --- a/apps/uload/apps/landing/src/content/config.ts +++ /dev/null @@ -1,17 +0,0 @@ -import { defineCollection, z } from 'astro:content'; - -const blogCollection = defineCollection({ - type: 'content', - schema: z.object({ - title: z.string(), - description: z.string(), - pubDate: z.date(), - author: z.string().optional(), - image: z.string().optional(), - tags: z.array(z.string()).optional(), - }), -}); - -export const collections = { - blog: blogCollection, -}; diff --git a/apps/uload/apps/landing/src/env.d.ts b/apps/uload/apps/landing/src/env.d.ts deleted file mode 100644 index acef35f17..000000000 --- a/apps/uload/apps/landing/src/env.d.ts +++ /dev/null @@ -1,2 +0,0 @@ -/// -/// diff --git a/apps/uload/apps/landing/src/layouts/BaseLayout.astro b/apps/uload/apps/landing/src/layouts/BaseLayout.astro deleted file mode 100644 index 081344dfb..000000000 --- a/apps/uload/apps/landing/src/layouts/BaseLayout.astro +++ /dev/null @@ -1,59 +0,0 @@ ---- -import '../styles/global.css'; -import Navigation from '../components/Navigation.astro'; -import Footer from '../components/Footer.astro'; - -interface Props { - title: string; - description?: string; - ogImage?: string; -} - -const { - title, - description = 'uLoad - Der intelligente URL-Shortener für Profis. Verkürzen Sie Links, erstellen Sie QR-Codes und analysieren Sie Klicks.', - ogImage = '/og-image.png', -} = Astro.props; -const canonicalURL = new URL(Astro.url.pathname, Astro.site); ---- - - - - - - - - - - {title} | uLoad - - - - - - - - - - - - - - - - - - - - - - -
- -
-