Add short-link sharing for feedback forms via shlink #2

Open
opened 2026-05-05 21:09:00 +00:00 by mAi · 1 comment

What

Let admins create memorable short links (e.g. https://msbls.de/vote) that redirect to a feedback form's long URL (https://fdbck.msbls.de/f/<32-char-slug>). Mirror the pattern flexsiebels already uses against m's shlink instance.

Reference: flexsiebels integration

  • Endpoint: flexsiebels/website/src/routes/api/share/+server.ts — POST wraps shlink REST v3 (/rest/v3/short-urls).
  • Env: SHLINK_URL (default https://msbls.de), SHLINK_API_KEY.
  • Schema: ShareCreateSchema (longUrl, customSlug?, maxVisits?, domain?).

Scope

Server

  • New src/lib/server/shlink.ts — port the createShortUrl() helper from flexsiebels' api/share/+server.ts. Same env vars. Throw on missing key.
  • New src/routes/api/admin/feedback/[id]/share/+server.ts (POST):
    • Auth-gated (admin only — copy the pattern from [id]/+server.ts).
    • Body: { customSlug?: string, maxVisits?: number }.
    • Constructs longUrl = \${PUBLIC_SITE_URL}/f/${instance.slug}``.
    • Calls createShortUrl({ longUrl, customSlug, maxVisits }).
    • Returns { shortUrl, shortCode, customSlug } or shlink's full response.
    • Stores the shortUrl on the instance for later display (new feedback_instances.short_url TEXT column — see Schema).
  • Add ShareCreateSchema to src/lib/schemas.ts (zod, mirror flexsiebels).

Schema

Migration: add short_url TEXT NULL to fdbck.feedback_instances (and short_code TEXT NULL if useful for revoke later). Apply via Supabase migration helper.

Admin UI

In src/routes/admin/feedback/[id]/+page.svelte, add a self-contained "Share" section (new block, don't restyle anything else — dokploy is restyling buttons in parallel; stay out of his way).

  • If instance.short_url exists: display it with a Copy button.
  • If not: input for customSlug (optional, e.g. "vote"), submit creates short link via POST and refreshes.
  • Help text: "Leave blank for a random short code, or pick a memorable slug like 'vote' or 'session-feedback'."
  • Show the resulting short URL prominently with copy button + open-in-new-tab.

Out of scope

  • Revoking / deleting a short URL (next iteration — would call DELETE /rest/v3/short-urls/{shortCode})
  • Listing all short URLs across instances (admin overview)
  • QR code generation
  • Per-link analytics dashboard (shlink already tracks visits — link to its admin UI from the panel as a v1 nice-to-have)

Acceptance

  • Admin can pick "create short link" on /admin/feedback/<id>, optionally with custom slug.
  • Short URL is stored on the instance and displayed on subsequent loads.
  • Short URL resolves to the long /f/ URL via shlink.
  • SHLINK_URL + SHLINK_API_KEY env vars wired into the Dokploy app config (head will set after merge — flag in your completion report so head knows to copy from flexsiebels.de-app).
  • Type-check + tests still pass.

How to work

Branch off main: mai/<your-name>/shlink-integration. dokploy is in parallel on mai/dokploy/button-systemDO NOT touch existing buttons, the icon system, feedback.css buttons, or any inline styles. Append only; let dokploy's restyle win for shared elements.

Two-three commits is fine (helper + endpoint + UI + migration). Push, head will merge after dokploy lands first to avoid conflicts.

## What Let admins create memorable short links (e.g. `https://msbls.de/vote`) that redirect to a feedback form's long URL (`https://fdbck.msbls.de/f/<32-char-slug>`). Mirror the pattern flexsiebels already uses against m's shlink instance. ## Reference: flexsiebels integration - Endpoint: `flexsiebels/website/src/routes/api/share/+server.ts` — POST wraps shlink REST v3 (`/rest/v3/short-urls`). - Env: `SHLINK_URL` (default `https://msbls.de`), `SHLINK_API_KEY`. - Schema: `ShareCreateSchema` (longUrl, customSlug?, maxVisits?, domain?). ## Scope ### Server - New `src/lib/server/shlink.ts` — port the `createShortUrl()` helper from flexsiebels' `api/share/+server.ts`. Same env vars. Throw on missing key. - New `src/routes/api/admin/feedback/[id]/share/+server.ts` (POST): - Auth-gated (admin only — copy the pattern from `[id]/+server.ts`). - Body: `{ customSlug?: string, maxVisits?: number }`. - Constructs `longUrl = \`${PUBLIC_SITE_URL}/f/\${instance.slug}\``. - Calls `createShortUrl({ longUrl, customSlug, maxVisits })`. - Returns `{ shortUrl, shortCode, customSlug }` or shlink's full response. - Stores the shortUrl on the instance for later display (new `feedback_instances.short_url TEXT` column — see Schema). - Add `ShareCreateSchema` to `src/lib/schemas.ts` (zod, mirror flexsiebels). ### Schema Migration: add `short_url TEXT NULL` to `fdbck.feedback_instances` (and `short_code TEXT NULL` if useful for revoke later). Apply via Supabase migration helper. ### Admin UI In `src/routes/admin/feedback/[id]/+page.svelte`, add a self-contained \"Share\" section (new block, don't restyle anything else — dokploy is restyling buttons in parallel; stay out of his way). - If `instance.short_url` exists: display it with a Copy button. - If not: input for `customSlug` (optional, e.g. \"vote\"), submit creates short link via POST and refreshes. - Help text: \"Leave blank for a random short code, or pick a memorable slug like 'vote' or 'session-feedback'.\" - Show the resulting short URL prominently with copy button + open-in-new-tab. ### Out of scope - Revoking / deleting a short URL (next iteration — would call `DELETE /rest/v3/short-urls/{shortCode}`) - Listing all short URLs across instances (admin overview) - QR code generation - Per-link analytics dashboard (shlink already tracks visits — link to its admin UI from the panel as a v1 nice-to-have) ## Acceptance - Admin can pick \"create short link\" on `/admin/feedback/<id>`, optionally with custom slug. - Short URL is stored on the instance and displayed on subsequent loads. - Short URL resolves to the long /f/<slug> URL via shlink. - `SHLINK_URL` + `SHLINK_API_KEY` env vars wired into the Dokploy app config (head will set after merge — flag in your completion report so head knows to copy from flexsiebels.de-app). - Type-check + tests still pass. ## How to work Branch off main: `mai/<your-name>/shlink-integration`. dokploy is in parallel on `mai/dokploy/button-system` — **DO NOT touch existing buttons, the icon system, feedback.css buttons, or any inline styles**. Append only; let dokploy's restyle win for shared elements. Two-three commits is fine (helper + endpoint + UI + migration). Push, head will merge after dokploy lands first to avoid conflicts.
Author

Branch: mai/hermes/fdbck-shlink-short-link (compare)

What landed

Server

  • src/lib/server/shlink.tscreateShortUrl() helper, ports flexsiebels api/share/+server.ts 1:1. Reads SHLINK_URL (default https://msbls.de) + SHLINK_API_KEY. Throws if key is unset.
  • POST /api/admin/feedback/[id]/share — auth-gated. Body { customSlug?, maxVisits? }. Builds longUrl = ${PUBLIC_SITE_URL}/f/${instance.slug}, calls shlink, persists short_url + short_code onto the instance, returns { shortUrl, shortCode, customSlug, instance }.
  • ShareCreateSchema in src/lib/schemas.tscustomSlug regex-restricted to [A-Za-z0-9_-]{1,64}, maxVisits positive int.
  • FeedbackInstance extended with short_url: string | null, short_code: string | null.

Schema

  • Migration fdbck_feedback_instances_add_short_url applied via Supabase MCP — adds short_url TEXT NULL and short_code TEXT NULL to fdbck.feedback_instances (idempotent ADD COLUMN IF NOT EXISTS).

Admin UI

  • New self-contained Share section on /admin/feedback/[id] — appears between the header and the tabs. Append-only: does not touch existing buttons, the icon system, or feedback.css classes — uses inline styles + existing fb-* classes so dokploy's parallel mai/dokploy/button-system work wins on shared elements.
  • Empty state: optional custom-slug input + "Create short link" button + help text.
  • Filled state: short URL with Copy + Open ↗ buttons + a collapsed "Replace with a different short link" details block.
  • Inline error banner for shlink-side failures.

⚠️ Action required for head before merge

SHLINK_URL + SHLINK_API_KEY must be copied from the flexsiebels.de Dokploy app to the fdbck.msbls.de Dokploy app config — otherwise the Share endpoint throws Shlink API key is not configured.

.env.example now documents both vars.

Verification

  • bun run check — 0 errors, 26 pre-existing warnings (none in changed files).
  • bun run test — 20 pass, 0 fail.
  • bun run build — succeeds.

Commits

  • c5d0b2a shlink server: helper + share endpoint + schema
  • 696b796 admin Share section + env-var docs

Out of scope (per brief)

  • DELETE / revoke of a short URL
  • QR codes
  • Per-link analytics (shlink already tracks visits — link to its admin UI is a future nice-to-have)
  • Listing short URLs across all instances

Ready for head to merge after dokploy's mai/dokploy/button-system lands, to avoid conflicts on the detail page.

## Done — shlink integration ready for review Branch: `mai/hermes/fdbck-shlink-short-link` ([compare](https://mgit.msbls.de/m/fdbck/compare/main...mai/hermes/fdbck-shlink-short-link)) ### What landed **Server** - `src/lib/server/shlink.ts` — `createShortUrl()` helper, ports flexsiebels `api/share/+server.ts` 1:1. Reads `SHLINK_URL` (default `https://msbls.de`) + `SHLINK_API_KEY`. Throws if key is unset. - `POST /api/admin/feedback/[id]/share` — auth-gated. Body `{ customSlug?, maxVisits? }`. Builds `longUrl = ${PUBLIC_SITE_URL}/f/${instance.slug}`, calls shlink, persists `short_url` + `short_code` onto the instance, returns `{ shortUrl, shortCode, customSlug, instance }`. - `ShareCreateSchema` in `src/lib/schemas.ts` — `customSlug` regex-restricted to `[A-Za-z0-9_-]{1,64}`, `maxVisits` positive int. - `FeedbackInstance` extended with `short_url: string | null`, `short_code: string | null`. **Schema** - Migration `fdbck_feedback_instances_add_short_url` applied via Supabase MCP — adds `short_url TEXT NULL` and `short_code TEXT NULL` to `fdbck.feedback_instances` (idempotent `ADD COLUMN IF NOT EXISTS`). **Admin UI** - New self-contained `Share` section on `/admin/feedback/[id]` — appears between the header and the tabs. **Append-only**: does not touch existing buttons, the icon system, or `feedback.css` classes — uses inline styles + existing `fb-*` classes so dokploy's parallel `mai/dokploy/button-system` work wins on shared elements. - Empty state: optional custom-slug input + "Create short link" button + help text. - Filled state: short URL with Copy + Open ↗ buttons + a collapsed "Replace with a different short link" details block. - Inline error banner for shlink-side failures. ### ⚠️ Action required for head before merge `SHLINK_URL` + `SHLINK_API_KEY` must be copied from the **flexsiebels.de** Dokploy app to the **fdbck.msbls.de** Dokploy app config — otherwise the Share endpoint throws `Shlink API key is not configured`. `.env.example` now documents both vars. ### Verification - `bun run check` — 0 errors, 26 pre-existing warnings (none in changed files). - `bun run test` — 20 pass, 0 fail. - `bun run build` — succeeds. ### Commits - [`c5d0b2a`](https://mgit.msbls.de/m/fdbck/commit/c5d0b2a) shlink server: helper + share endpoint + schema - [`696b796`](https://mgit.msbls.de/m/fdbck/commit/696b796) admin Share section + env-var docs ### Out of scope (per brief) - DELETE / revoke of a short URL - QR codes - Per-link analytics (shlink already tracks visits — link to its admin UI is a future nice-to-have) - Listing short URLs across all instances Ready for head to merge **after** dokploy's `mai/dokploy/button-system` lands, to avoid conflicts on the detail page.
Sign in to join this conversation.
No Label
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: m/fdbck#2
No description provided.