Repository navigation
feat(admin): affiliation et clics de réservation (A-09) - #501
Open
Nascimento95 wants to merge 11 commits into
Open
Nascimento95 wants to merge 11 commits into
Nascimento95 wants to merge 11 commits into
Conversation
…tner link of a place (A-09) Migration 0018, additive: affiliate_programs (name, network, commission, cookie, active), booking_clicks (step, origin of the link; no foreign key to the step, as editing a route rewrites its steps and a cascade would erase the clicks), and places.partner_booking_url (https only) and partner_program_id (needs a link). user_id of a click stays null: the redirect opens in the browser, without a session. Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
…link a step shows (A-09) Schemas of the programs and of the bookable steps, and resolveBookingLink, the one place of the rule (D-048): the creator's link first, the partner link of Widoo only when the creator set none and unless its program is inactive. Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
GET, POST and PATCH /admin/affiliate-programs, for editors and admins: name (unique, whatever the case), network, commission note, cookie days (0 to 365), active. A patch changes only the fields sent; each write is journaled with its before and after. An inactive program no longer lends its links. Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
… (A-09) PATCH /admin/places/:id takes partnerBookingUrl (https) and partnerProgramId, sent together or not at all: left out, the place keeps its link. A program needs a link, and must exist. The sheet of a place reads both, and the journal keeps them before and after. Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
…the step (A-09) GET /v1/go/:stepId, public: counts the click in booking_clicks, then redirects (302) to the link the step shows, the creator's before the partner's of Widoo. It only redirects to a link stored for a step of a published route (https), never to an address the caller gives; anything else is a 404 that counts nothing. Limited to 60 a minute and per address, never cached nor indexed. Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
… the clicks of 30 days (A-09) GET /admin/bookable-steps, for editors and admins: the steps of published routes that ask for a booking or carry a link, most clicked first, each with the link it shows and where it comes from (creator, creator affiliate, partner of Widoo). withoutPartnerLink keeps the places with no partner link: the ones to sign up for first. Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
Affiliation, for editors and admins: the programs as a table (network, commission, cookie, places that name it, status) and the detail of one next to it, with the warning that an inactive program no longer lends its links. Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
…A-09) « Ajouter un programme » and « Modifier » open a window with the name, network, commission note and cookie days; « Désactiver » and « Activer » switch a program. A name already taken, a refused field and any other failure are told apart in a toast. Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
…nd its clicks (A-09) The second tab of Affiliation: each bookable step with the link it shows and where it comes from (creator, creator affiliate, partner of Widoo), its clicks of the last 30 days, and a link to the sheet of its place. « Lieux sans lien partenaire » keeps the places to sign up for first. Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
Two fields in the sheet of a place: the partner link (https, checked in the browser at once) and, once there is a link, the program it belongs to (an inactive one is marked). A field the API refuses (422) is now told as a refused field instead of a general failure, and the page scrolls to the error, as the button is at the bottom of a long form. Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
Nascimento95
requested review from
IlanAMG and
PaulThiberville
as code owners
October 16, 2026 10:56
This was referenced Oct 16, 2026
Open
1 of 2 tasks
This branch has not been deployed
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Résultat et problème
Widoo n'avait aucun moyen de compter les clics sur « Réserver », ni de gérer ses programmes d'affiliation, ni de savoir quelles étapes réservables n'ont pas encore de lien partenaire. A-09 « Affiliation » le fait, pour l'éditeur et l'admin.
GET /v1/go/:stepId(public) : compte le clic dansbooking_clicks, puis redirige (302) vers le lien que l'étape affiche, celui du créateur d'abord, sinon le lien partenaire de Widoo (D-048). Il ne redirige que vers un lien déjà enregistré enhttpspour une étape d'un parcours publié, jamais vers une adresse donnée par l'appelant ; tout le reste est un 404 qui ne compte rien. Limité à 60 par minute et par adresse.PATCH /admin/places/:id), le lien en https et son programme, ensemble ou pas du tout ; un programme demande un lien.resolveBookingLink(packages/shared), que/goet la liste utilisent.admin_actions.Limites
GET /routes/:idn'existe pas (ticket Exposer GET /routes/:id et /routes/:id/timeline, stocker computed #36). Il devra appelerresolveBookingLinket joindre le lieu et son programme. Tant qu'il n'existe pas, aucun lien partenaire ne s'affiche dans l'app./goest le ticket mobile Passer « Réserver » par /go/:stepId pour compter les clics #345 (Paul). L'adresse est/v1/go/:stepId, comme toutes les routes de l'API (le ticket écrithttps://<api>/go/:stepId).booking_clicks.user_idreste vide : la redirection s'ouvre dans le navigateur, sans session. La colonne est prévue par le wiki, et son lien est coupé à la purge d'un compte.Fixes #344
Écrans : A-09, A-04 (champs du lien partenaire)
Dépendance : PR empilée sur #500 (#348, base
issue/348-settings-and-log), elle-même sur #499 (#341), #479, #398, #365 et #363.Comment vérifier
pnpm install,docker-compose up -d,pnpm --filter @widoo/api db:migrate && pnpm --filter @widoo/api db:seed,pnpm dev.https://…: le champ « Programme du lien » apparaît ; un lien enhttp://est refusé dès l'enregistrement.http://localhost:8080/v1/go/<identifiant d'une étape avec un lien>dans le navigateur : redirection vers le lien, et le compteur de l'étape augmente de 1. Un identifiant inconnu donne un 404 sans redirection.Tests : l'ordre créateur puis partenaire, le programme inactif, un lien partenaire sans programme, le 404 sans clic pour une étape sans lien, d'un parcours non publié ou inconnue, le délai de moins de 200 ms, les droits (moderator refusé), la liste des étapes (origines, filtre, clics sur 30 jours), les programmes (unicité du nom sans tenir compte de la casse, patch partiel, journal), le lien partenaire d'un lieu (ensemble, conservé si absent, refusé hors https ou sans lien).
pnpm lint && pnpm typecheck && pnpm testverts en local (chaque commit passe lint et types) ; seuls les tests chronométrés de l'API échouent parfois en suite complète (délai de 5 s) et passent seulsFormatage mécanique : non
Risque
Niveau : 3 — nouvelle table et migration, endpoint public non authentifié qui écrit et redirige.
Taille : tous les commits sous 400 lignes utiles (le plus gros : 394). Le snapshot de la migration (
meta/0018_snapshot.json) est généré par drizzle-kit.Revue OWASP
PATCH /admin/places/:idreste réservé à l'éditeur et à l'admin./goest public par nature : il ne lit rien du compte et n'expose que le lien déjà affiché de l'étape./gone prend aucune adresse en entrée, il lit le lien stocké de l'étape ou du lieu, et le refuse s'il n'est pas enhttps. Les liens sont déjà tenus àhttpsà l'écriture, par le schéma et par une contrainte de la base (places_partner_link_check).admin_actions(avant, après) dans la transaction du changement.user_idreste vide. Réponsesno-store,noindex,referrer-policy: no-referrer.Retour arrière
Revert de la PR. Migration
0018additive : deux tables et deux colonnes nullables surplaces. Un revert du code laisse les tables et colonnes sans effet. Pour les supprimer, retirer d'abord les liens partenaires des lieux (partner_program_id, puispartner_booking_url) avant de supprimeraffiliate_programs. Les clics comptés sont des statistiques sans donnée personnelle : les garder ne coûte rien.🤖 Generated with Claude Code