From c0ca5feb6f059e584bbd4df543bd6b1a78cfca31 Mon Sep 17 00:00:00 2001 From: louispaulb Date: Fri, 22 May 2026 10:15:43 -0400 Subject: [PATCH] =?UTF-8?q?feat(campaigns):=20gift=20redirect=20wrapper=20?= =?UTF-8?q?=E2=80=94=20own=20expiry=20+=20reusable=20links?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Each campaign recipient now gets a short opaque token (10 base64url chars, ~60 bits entropy). The email contains https://msg.gigafibre.ca/g/ which 302-redirects to the underlying Giftbit shortlink — but ONLY if the recipient hasn't passed our own expires_at and we haven't revoked the token. This gives us two new operational capabilities: 1. End-date control independent of Giftbit. The wizard now has a "Expiration interne (jours)" field (default 90) that sets our own deadline. Useful when the Giftbit gift is valid 12 months but the campaign offer should expire in 30 days. 2. Reuse of unredeemed gifts. After our expiry, the old wrapper stops working but the Giftbit URL is still valid on their side. Pasting that same gift_url into a new campaign (via the manual-add dialog) generates a NEW token pointing to the same Giftbit gift — the original recipient's old wrapper URL says "expired", the new recipient gets a fresh window. Per-recipient new fields: - gift_token short ID used in the wrapper URL - gift_expires_at ISO timestamp of our cutoff - gift_revoked manual kill-switch (false by default) - gift_redirected_count clicks that successfully reached Giftbit - gift_first_redirected_at first successful redirect timestamp Routing: - GET /g/:token — public, validates and 302s (or expired-page) - Mailjet click event handler updated to recognise wrapper URLs alongside legacy gft.link/giftbit.com URLs. - /view (browser fallback for in-email rendering) also wraps the gift link so expiry/revoke is honoured consistently. Bootstrap rebuilds the in-memory token→recipient index by scanning all campaign JSONs on startup — no separate index file to keep in sync. CSV report adds gift_token, gift_expires_at, gift_revoked, gift_redirected_count, gift_first_redirected_at. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.7 --- .../campaigns/pages/CampaignNewPage.vue | 11 +- services/targo-hub/lib/campaigns.js | 158 +++++++++++++++++- services/targo-hub/server.js | 3 + 3 files changed, 169 insertions(+), 3 deletions(-) diff --git a/apps/ops/src/modules/campaigns/pages/CampaignNewPage.vue b/apps/ops/src/modules/campaigns/pages/CampaignNewPage.vue index 33cadca..8a8e27a 100644 --- a/apps/ops/src/modules/campaigns/pages/CampaignNewPage.vue +++ b/apps/ops/src/modules/campaigns/pages/CampaignNewPage.vue @@ -66,7 +66,11 @@ - + + Délai après lequel le lien intermédiaire /g/<token> expire et ne redirige plus. Le lien Giftbit sous-jacent reste valide chez Giftbit jusqu'à leur propre date — utile pour réassigner un cadeau non utilisé à un autre client. + +