Aller au contenu
ADITUS-Queue

La salle d'attente virtuelle pour l'entreprise

ADITUS-Queue est une salle d'attente virtuelle autonome qui protège n'importe quel site web, API ou service en ligne contre les pics de trafic. Elle s'intègre parfaitement à la plateforme de billetterie ADITUS — et se déploie tout aussi indépendamment devant n'importe quelle application web. Les visiteurs sont retenus dans une salle d'attente hébergée et redirigés strictement dans l'ordre d'arrivée, à un rythme configuré par minute. L'intégration va du simple lien gateway ou de la balise de script, sans aucune infrastructure côté exploitant, à l'API REST pure, en passant par une application au niveau du reverse proxy ou du CDN.

Nouveau : le rythme de redirection autorégulé. La file lit un health check de votre boutique et ajuste le rythme d'elle-même — plus de visiteurs quand la boutique a des réserves, un soulagement immédiat quand elle est sous pression.

Malgré toute cette richesse : la configuration prend des minutes, pas des jours. Un lien publié ou une balise de script — aucune infrastructure, aucun déploiement, aucune modification de code de votre côté.

Démarrage rapide : en ligne en moins de 2 minutes

Protégez votre application en moins de 2 minutes : copiez la balise de script dans votre head ou utilisez le lien gateway. Aucune modification de votre infrastructure serveur. Ce n'est que si vous voulez un contrôle maximal que vous activez les fonctionnalités avancées optionnelles — tout le reste sur cette page n'est justement que cela : de la profondeur optionnelle pour plus tard.

503
Classiquerigide & surchargé — tous les visiteurs atteignent la boutique en même temps
Salle d'attenteLe health check régule le rythme
ADITUS-Queuedynamique & protégé — redirection exactement au rythme que la boutique supporte
  1. 1

    Créer une salle d'attente

    Dans l'administration ADITUS : nom, adresse de la boutique, rythme de redirection par minute. Tout le reste est préréglé avec des valeurs par défaut pertinentes.

  2. 2

    Copier une ligne

    Soit publier le lien gateway prêt à l'emploi à la place du lien de la boutique — soit insérer la balise de script préparée dans la page de la boutique, exactement comme un snippet d'analytics.

  3. 3

    Terminé — la file est armée

    En dessous du rythme de redirection, les visiteurs ne voient jamais la salle d'attente. Ce n'est qu'en cas de pic que la file intervient — hébergée, mise à l'échelle et exploitée par nos soins.

Évolue avec vous : trois niveaux de protection

La puissance de la file est un chemin de montée en gamme, pas un prérequis. Le niveau 1 couvre à lui seul la grande majorité des cas d'usage.

Niveau 1 : protection standardLien gateway ou balise de script. Immédiatement opérationnel, zéro infrastructure — suffisant pour la plupart des cas standard.Immédiatement opérationnel
Niveau 2 : protection avancéeLe rythme de redirection autorégulé via le health check de la boutique — la file actionne le curseur à votre place.Optionnel
Niveau 3 : protection bulletproofDurcissement au niveau de l'edge via vérification JWT hors ligne dans Nginx, Caddy ou le CDN — pour les équipes DevOps.Optionnel — pour les équipes DevOps

Intégration : deux variantes

Le choix de la variante dépend d'une seule question : le lien de la boutique publié peut-il être modifié ? Si oui, le lien gateway est le meilleur choix — le trafic n'atteint jamais la boutique avant la redirection. Si l'URL de la boutique publiée est figée, la balise de script protège la boutique sans rien changer à sa publication. Au-delà de ces deux options, la vérification peut être appliquée dans le reverse proxy ou le CDN (ci-dessous), pilotée directement via l'API REST, ou vérifiée dans n'importe quel langage backend avec une bibliothèque JWT — Node.js, PHP, Java, .NET, Python, Go.

Gateway-LinkScript-TagReverse proxy / CDNREST-APIVérification backend (JWT, tout langage)

Variante A : le lien gateway (recommandé)

Chaque salle d'attente fournit sa propre URL d'entrée. Elle est publiée partout où figurerait sinon le lien de la boutique — newsletter, site web, réseaux sociaux. La file reçoit la requête et décide côté serveur en une seule étape : en dessous du rythme de redirection, le visiteur est redirigé directement vers l'adresse configurée de la boutique et ne remarque pas du tout la file ; une fois le rythme dépassé, le visiteur arrive dans la salle d'attente et est redirigé automatiquement quand c'est son tour. La boutique elle-même ne reçoit aucun trafic avant la redirection — les requêtes sont absorbées avant d'atteindre l'infrastructure de la boutique.

newsletter.html
<!-- Der veröffentlichte Shop-Link zeigt auf die Queue statt auf den Shop: -->
<a href="https://developers.aditus.com/queue/<slug>/enter">Tickets kaufen</a>

Pour cette variante, l'adresse cible de la boutique (Ziel-URL) doit être configurée sur la file — c'est l'adresse vers laquelle les visiteurs redirigés sont envoyés. Les visiteurs autorisés arrivent sur la boutique avec un token d'accès signé dans l'URL — un JWT HS256 standard que la boutique peut, en option, vérifier hors ligne dans son propre backend à l'aide du secret partagé. La structure, les claims et un exemple backend sont documentés ci-dessous. Remarque : le gateway protège le point d'entrée publié ; les visiteurs qui connaissent directement l'URL de la boutique peuvent le contourner. Si cela compte, combinez le lien gateway avec la balise de script ou vérifiez le token dans le backend de la boutique.

Variante B : la balise de script

Lorsque le lien publié de la boutique ne peut pas être modifié, l'intégration se résume à une seule balise de script. Elle est livrée avec les pages de la boutique — de la même manière qu'un snippet d'analytics — et doit être présente sur chaque page que la salle d'attente doit protéger. Un placement dans le <head> avec l'attribut defer est recommandé ; la position exacte n'est pas critique.

shop.html
<!-- Auf jeder zu schützenden Shop-Seite im <head>: -->
<script src="https://developers.aditus.com/queue/<slug>/embed.js" defer></script>

La balise exacte pour une salle d'attente donnée — avec le slug correct déjà inséré — est disponible dans l'administration ADITUS, par file. Le script effectue trois vérifications à chaque chargement de page :

  1. 1

    Le visiteur détient un laissez-passer valide

    Rien ne se passe. Le laissez-passer est conservé par session de navigateur ; le visiteur utilise la boutique sans interruption.

  2. 2

    Le visiteur revient de la salle d'attente

    Le token d'accès présent dans l'URL est vérifié côté serveur (signature, appartenance à la file, expiration). S'il est valide, un laissez-passer de session est enregistré et le token est retiré de la barre d'adresse. Les tokens invalides ou expirés renvoient le visiteur dans la salle d'attente.

  3. 3

    Le visiteur n'a pas de laissez-passer

    Si personne n'attend actuellement, le visiteur est admis en silence en arrière-plan et reste sur la page — la salle d'attente n'apparaît jamais. Ce n'est que lorsque le rythme de redirection configuré est dépassé et qu'une file s'est formée que le visiteur est redirigé vers la salle d'attente ; la page courante est transmise comme URL de retour validée, si bien qu'après la redirection le visiteur arrive exactement sur la page qu'il avait initialement demandée.

Défaillance ouverte

Si le service de file est injoignable ou si la file n'existe pas, le script ne fait rien et la boutique reste pleinement utilisable. Une panne de la salle d'attente ne bloque jamais la boutique.

Aucune redirection ouverte

Les URL de retour sont validées côté serveur par rapport aux domaines configurés pour la file. La salle d'attente ne redirige que vers des pages de la boutique enregistrée.

Durcissement : appliquer le contrôle d'accès au niveau de l'edge proxy

Mise à niveau optionnelle — pour les équipes DevOpsNon requis pour la configuration ci-dessus

Les deux variantes ci-dessus protègent le point d'entrée publié. Si la boutique doit rester injoignable sans autorisation, même pour les visiteurs qui connaissent directement son URL, la vérification passe devant la boutique — dans le reverse proxy ou le CDN qui termine son trafic. La logique tient toujours dans les trois mêmes étapes : récupérer le token depuis le paramètre d'URL aditus_queue_token au retour de la salle d'attente et le stocker dans un cookie ; à chaque requête, vérifier le token du cookie comme un JWT HS256 standard avec le secret partagé (issuer aditus-queue, audience le slug de la file, expiration) ; sans token valide, rediriger vers la salle d'attente à l'adresse https://developers.aditus.com/queue/<slug>. La vérification est hors ligne — le proxy n'appelle jamais la file et n'ajoute aucune latence. Les esquisses suivantes montrent le schéma pour quatre environnements courants ; adaptez-les à votre propre environnement.

NginxModule njs — vérification directement dans le proxy, sans service supplémentaire.Snippet inclus
CaddyPlugin jwtauth — pure configuration, pas une seule ligne de code.Snippet inclus
CloudflareWorker au niveau de l'edge — appliqué dans le monde entier avant que le trafic n'atteigne la boutique.Snippet inclus
AWS CloudFrontLambda@Edge — la vérification s'exécute dans le réseau mondial d'AWS.Snippet inclus
JWT HS256 standardVérification hors ligne — aucun rappelAucune latence ajoutéeCompatible avec tout reverse proxy
Nginx (njs)
# Skizze: Nginx mit njs (js_import) — prüft den Zugriffs-Token als HS256-JWT
# direkt am Proxy, ohne Rückruf an die Queue. An die eigene Umgebung anpassen.

# nginx.conf:
#   env ADITUS_QUEUE_SECRET;
#   js_import queue from /etc/nginx/queue.js;
#   server {
#     location /       { js_content queue.gate; }
#     location @shop   { proxy_pass http://shop_backend; }
#   }

// /etc/nginx/queue.js:
const crypto = require('crypto');
const SLUG = '<slug>';
const SECRET = process.env.ADITUS_QUEUE_SECRET; // Shared Secret der Queue

function claims(token) {
  const p = token.split('.');
  if (p.length !== 3) return null;
  const sig = crypto.createHmac('sha256', SECRET)
    .update(p[0] + '.' + p[1]).digest('base64url');
  if (sig !== p[2]) return null;
  const c = JSON.parse(Buffer.from(p[1], 'base64url'));
  const ok = c.iss === 'aditus-queue' && c.aud === SLUG && c.exp > Date.now() / 1000;
  return ok ? c : null;
}

function gate(r) {
  const fromUrl = r.args.aditus_queue_token;
  const m = (r.headersIn.Cookie || '').match(/(?:^|;\s*)aditus_queue=([^;]+)/);
  const token = fromUrl || (m && m[1]);
  if (!token || !claims(token)) {
    // Kein gültiger Token -> zurück in den Warteraum
    r.return(302, 'https://developers.aditus.com/queue/' + SLUG);
    return;
  }
  if (fromUrl) {
    // Token aus der Rücksprung-URL in ein Sitzungs-Cookie übernehmen
    r.headersOut['Set-Cookie'] =
      'aditus_queue=' + fromUrl + '; Path=/; Secure; HttpOnly; Max-Age=600';
  }
  r.internalRedirect('@shop');
}

export default { gate };
Caddyfile
# Skizze: Caddy mit dem jwtauth-Plugin (github.com/ggicci/caddy-jwt).
# Token kommt beim Rücksprung als ?aditus_queue_token=… oder danach als Cookie;
# jwtauth prüft beide Quellen. An die eigene Umgebung anpassen.
shop.example.com {
  route {
    jwtauth {
      sign_key {env.ADITUS_QUEUE_SECRET}
      sign_alg HS256
      from_query aditus_queue_token
      from_cookies aditus_queue
      issuer_whitelist aditus-queue
      audience_whitelist <slug>
      user_claims qnr
    }
    # Token aus der URL einmalig in ein Cookie übernehmen
    @rueckkehr query aditus_queue_token=*
    header @rueckkehr Set-Cookie "aditus_queue={http.request.uri.query.aditus_queue_token}; Path=/; Secure; HttpOnly; Max-Age=600"
    reverse_proxy shop_backend:8080
  }
  # Ohne gültigen Token: zurück in den Warteraum
  handle_errors {
    @unauth expression {http.error.status_code} == 401
    redir @unauth https://developers.aditus.com/queue/<slug> 302
  }
}
Cloudflare Worker
// Skizze: Cloudflare Worker vor dem Shop — prüft den HS256-JWT offline per
// WebCrypto. Secret als Worker-Secret ADITUS_QUEUE_SECRET hinterlegen.
const SLUG = "<slug>";
const ROOM = "https://developers.aditus.com/queue/" + SLUG;

export default {
  async fetch(req, env) {
    const url = new URL(req.url);
    const fromUrl = url.searchParams.get("aditus_queue_token");
    const m = (req.headers.get("Cookie") || "").match(/(?:^|;\s*)aditus_queue=([^;]+)/);
    const token = fromUrl || (m && m[1]);
    if (!token || !(await valid(token, env.ADITUS_QUEUE_SECRET))) {
      return Response.redirect(ROOM, 302); // zurück in den Warteraum
    }
    if (fromUrl) {
      // Token in ein Cookie übernehmen und die URL bereinigen
      url.searchParams.delete("aditus_queue_token");
      return new Response(null, {
        status: 302,
        headers: {
          Location: url.toString(),
          "Set-Cookie": "aditus_queue=" + token +
            "; Path=/; Secure; HttpOnly; Max-Age=600",
        },
      });
    }
    return fetch(req); // gültiger Pass -> durch zum Shop
  },
};

async function valid(token, secret) {
  const p = token.split(".");
  if (p.length !== 3) return false;
  const key = await crypto.subtle.importKey(
    "raw", new TextEncoder().encode(secret),
    { name: "HMAC", hash: "SHA-256" }, false, ["verify"],
  );
  const ok = await crypto.subtle.verify(
    "HMAC", key, b64url(p[2]),
    new TextEncoder().encode(p[0] + "." + p[1]),
  );
  if (!ok) return false;
  const c = JSON.parse(new TextDecoder().decode(b64url(p[1])));
  return c.iss === "aditus-queue" && c.aud === SLUG && c.exp > Date.now() / 1000;
}

function b64url(v) {
  return Uint8Array.from(
    atob(v.replace(/-/g, "+").replace(/_/g, "/")),
    (ch) => ch.charCodeAt(0),
  );
}
AWS CloudFront (Lambda@Edge)
// Skizze: AWS CloudFront mit Lambda@Edge (Viewer-Request, Node.js).
// Gleiches Muster: Token aus ?aditus_queue_token oder Cookie, HS256 offline
// prüfen, ohne gültigen Token in den Warteraum umleiten.
// Hinweis: Lambda@Edge hat keine Umgebungsvariablen — das Secret z. B. beim
// Deployment einbetten oder aus SSM/Secrets Manager cachen.
'use strict';
const crypto = require('crypto');
const SLUG = '<slug>';
const ROOM = 'https://developers.aditus.com/queue/' + SLUG;
const SECRET = '<ADITUS_QUEUE_SECRET>';

exports.handler = async (event) => {
  const req = event.Records[0].cf.request;
  const qs = new URLSearchParams(req.querystring || '');
  const fromUrl = qs.get('aditus_queue_token');
  const cookie = (req.headers.cookie || []).map((h) => h.value).join('; ');
  const m = cookie.match(/(?:^|;\s*)aditus_queue=([^;]+)/);
  const token = fromUrl || (m && m[1]);

  if (!token || !valid(token)) {
    return redirect(ROOM); // zurück in den Warteraum
  }
  if (fromUrl) {
    // Token in ein Cookie übernehmen und die URL bereinigen
    qs.delete('aditus_queue_token');
    const clean = req.uri + (qs.toString() ? '?' + qs.toString() : '');
    return redirect(clean, {
      'set-cookie': [{ key: 'Set-Cookie', value:
        'aditus_queue=' + token + '; Path=/; Secure; HttpOnly; Max-Age=600' }],
    });
  }
  return req; // gültiger Pass -> durch zum Shop (Origin)
};

function valid(token) {
  const p = token.split('.');
  if (p.length !== 3) return false;
  const sig = crypto.createHmac('sha256', SECRET)
    .update(p[0] + '.' + p[1]).digest();
  const got = Buffer.from(p[2], 'base64url');
  if (got.length !== sig.length || !crypto.timingSafeEqual(sig, got)) {
    return false;
  }
  const c = JSON.parse(Buffer.from(p[1], 'base64url'));
  return c.iss === 'aditus-queue' && c.aud === SLUG && c.exp > Date.now() / 1000;
}

function redirect(location, extraHeaders) {
  return {
    status: '302',
    headers: Object.assign(
      { location: [{ key: 'Location', value: location }] },
      extraHeaders || {},
    ),
  };
}

Remarque : avec une vérification active au niveau de l'edge, chaque visiteur a besoin d'un token — y compris ceux qui, en dessous du rythme de redirection, passeraient sinon en silence. Publiez pour cela le lien gateway (variante A), ou laissez le proxy rediriger les visiteurs sans token vers la salle d'attente ; celle-ci délivre immédiatement un token lorsque la file est vide.

Configuration : ce dont ADITUS a besoin de votre part

La salle d'attente est configurée par ADITUS. Pour la mise en place, fournissez les éléments suivants :

Visuel (optionnel)

Une image d'en-tête pour la page de salle d'attente, par ex. le key visual de l'événement. Format paysage, au moins 920 × 380 pixels (affichée jusqu'à 460 px de largeur, rognée à une hauteur maximale de 190 px), JPG ou PNG, fournie sous forme d'URL HTTPS publiquement accessible ou de fichier à ADITUS.

Texte (optionnel)

Un court message affiché sous le titre de la salle d'attente, par ex. une note sur l'ouverture des ventes ou le temps d'attente prévu. Texte brut, les sauts de ligne sont conservés ; longueur recommandée jusqu'à environ 300 caractères. Le texte est affiché tel quel — si vous vous adressez à un public international, fournissez-le dans la langue appropriée ou de manière bilingue.

Couleur d'accentuation (optionnel)

Une couleur de marque sous forme de valeur hexadécimale (par ex. #0a63c9). Elle colore la barre de progression et l'indicateur en direct sur la page de salle d'attente ; sans valeur, la couleur par défaut d'ADITUS est utilisée. Avec le visuel et le texte, la salle d'attente adopte ainsi l'identité de l'organisateur.

Domaines de la boutique

Les domaines des pages sur lesquelles le script s'exécutera (par ex. shop.example.com). Ils définissent quelles URL de retour la salle d'attente accepte.

Nom d'affichage, URL cible, rythme

Le titre de la salle d'attente (par ex. le nom de l'événement), l'URL cible pour les visiteurs redirigés (requise pour le lien gateway — c'est l'adresse de la boutique vers laquelle le gateway redirige) et le rythme de redirection en visiteurs par minute. Le rythme est le seuil de débit : tant qu'il arrive moins de visiteurs que le rythme ne l'autorise, tout le monde passe sans salle d'attente. Il est ajustable à tout moment en cours d'exploitation.

Se met à jour automatiquement (toutes les quelques secondes)
1

Numéro d'attente — attribué une fois à l'ouverture de la page et conservé pendant toute l'attente, même après un rechargement.

2

Position et numéro redirigé — combien de numéros précèdent le vôtre et jusqu'à quel numéro la redirection est actuellement ouverte. Le numéro redirigé croît en continu avec le rythme de redirection.

3

Barre de progression — visualise à quel point la redirection s'est déjà rapprochée de votre propre numéro.

4

Attente estimée — calculée à partir de la position actuelle et du rythme de redirection ; elle se raccourcit à mesure que la redirection progresse. Dès que votre numéro est autorisé, la page redirige automatiquement vers la boutique — sans aucune action de votre part.

Configuré une seule fois (statique)
A

Image d'en-tête — optionnelle, par ex. le key visual de l'événement.

B

Nom d'affichage — le titre de la salle d'attente, par ex. le nom de l'événement.

C

Message — texte optionnel sous le titre, affiché tel quel.

Schéma de la page de salle d'attente : les repères corail sont des valeurs en direct qui se mettent à jour automatiquement, les repères gris sont configurés une seule fois.
La salle d'attente hébergée avec image d'en-tête et message : le numéro d'attente, la position, le numéro redirigé et l'attente estimée se mettent à jour automatiquement.

La page de salle d'attente elle-même est bilingue (allemand/anglais). La langue est sélectionnée automatiquement d'après le réglage du navigateur du visiteur ; aucune configuration n'est nécessaire.

Exploitation : le tableau de bord en direct

Pendant l'ouverture des ventes, ADITUS surveille chaque salle d'attente dans un tableau de bord en direct : des jauges affichent le nombre de personnes en attente, l'afflux de nouveaux visiteurs par rapport au rythme de redirection, le rythme de redirection lui-même (avec son plafond configuré lorsque le rythme autorégulé est actif) et l'attente estimée pour les nouveaux arrivants. Un graphique à deux séries compare l'attente et l'afflux dans le temps, et les instances de file qui traitent le trafic signalent leur propre charge — CPU, mémoire et débit de requêtes. Le rythme de redirection peut être ajusté à tout moment en cours d'exploitation — par exemple lorsque la boutique montre des réserves.

Le tableau de bord en direct dans l'administration ADITUS, actualisé toutes les 3 secondes pendant l'ouverture des ventes.

Exploitation : tests de charge et health check

La robustesse de la file n'est pas seulement affirmée — elle est testée régulièrement. Depuis l'administration ADITUS, des tests de charge envoient de vraies requêtes vers une salle d'attente de test dédiée sur le système de production (les salles d'attente productives ne sont jamais touchées). Un test simule le parcours visiteur — inscription et interrogation du statut — à un rythme et une durée configurables. Des jauges en direct affichent le débit de requêtes atteint, la latence médiane et p95 ainsi que le taux d'erreur ; un graphique par seconde compare le débit à la latence, et chaque exécution est conservée dans un historique pour que les résultats restent comparables dans le temps. Les tests s'exécutent aussi selon une planification récurrente, et une exécution planifiée nettement moins bonne que les précédentes comparables est signalée automatiquement.

Un test de charge contre la file de production : KPI en direct, graphique par seconde, les instances de file actives pendant le test et l'historique des exécutions passées.

Pour la supervision externe, le service de file expose un health check public à /queue/healthz. Il répond sans authentification et sans accès à la base de données — un simple signal de disponibilité pour la supervision de disponibilité. Pendant un test de charge, l'administration affiche en plus les instances de file autodéclarées avec CPU, mémoire, latence de l'event loop et débit de requêtes ; sous charge, la plateforme démarre automatiquement des instances supplémentaires, et le test le rend visible.

Exploitation : le rythme de redirection autorégulé

Mise à niveau optionnelle — un rythme fixe suffit

Le rythme de redirection est le seul curseur qui décide de tout pendant une ouverture des ventes — et jusqu'ici, quelqu'un devait le surveiller. C'est fini : la file peut réguler le rythme elle-même, pilotée par l'état réel de la boutique protégée. Le résultat est une salle d'attente qui vend, à chaque instant, aussi vite que la boutique peut le supporter en toute sécurité — sans que personne n'ait à toucher un curseur.

Plein débit, zéro risque

Tant que la boutique est saine, le rythme monte par petits paliers et les réserves inutilisées se transforment en ventes. Dès que la boutique montre des signes de tension, le rythme chute nettement — volontairement asymétrique : le soulagement est immédiat, la charge revient avec prudence.

Fail-safe par conception

Un health check injoignable n'ouvre jamais davantage les portes : le rythme gèle d'abord, puis tombe au minimum configuré. La boutique est protégée précisément quand personne ne regarde.

Vos règles, en toute transparence

Vous définissez ce que « sain » signifie — temps de réponse, charge CPU, n'importe quelle métrique que votre boutique remonte. Chaque ajustement automatique est enregistré et visible dans le tableau de bord en direct, avec la règle qui l'a déclenché.

Au lieu d'ajuster le rythme de redirection à la main, une salle d'attente peut le réguler automatiquement à partir d'un health check de la boutique protégée. ADITUS interroge une URL de santé de la boutique à un intervalle configurable et évalue le temps de réponse et, en option, des champs numériques de la réponse JSON par rapport à des règles définies par l'exploitant (par exemple : temps de réponse inférieur à 500 ms, charge CPU inférieure à 0,8). Tant que la boutique est saine, le rythme est augmenté lentement par petits paliers ; dès qu'une règle est enfreinte, il est abaissé rapidement d'un pourcentage — volontairement asymétrique, afin que la boutique soit soulagée immédiatement mais que la charge revienne avec prudence. Le rythme reste toujours dans les limites d'un minimum et d'un maximum configurés.

Si le endpoint de santé ne répond pas, le système bascule en mode fail-safe : le rythme est d'abord gelé, puis, après plusieurs échecs consécutifs, il tombe au minimum configuré — un health check injoignable n'ouvre jamais davantage les portes. Chaque ajustement automatique est enregistré et visible dans le tableau de bord en direct, et avant que l'automatisme ne puisse être activé, le endpoint doit passer avec succès un test unique lancé depuis l'administration.

Le endpoint de santé côté boutique reste trivial : une URL HTTPS, accessible sans authentification, répondant en 2xx. Un corps JSON est optionnel — tous les champs numériques (les objets imbriqués sont aplatis en chemins pointés) deviennent des métriques auxquelles les règles peuvent faire référence :

Exemple de réponse de santé de la boutique
{
  "status": "ok",
  "responseBudgetMs": 500,
  "metrics": {
    "cpuLoad": 0.42,
    "dbPoolWaiting": 0,
    "openCheckouts": 118
  }
}

// Nutzbare Messwerte (Punktpfade):
//   responseBudgetMs, metrics.cpuLoad, metrics.dbPoolWaiting, metrics.openCheckouts
// Dazu immer verfügbar: die gemessene Antwortzeit (ms).

Exploitation : protection anti-bot par preuve de travail

Pour les ouvertures de ventes très demandées, une salle d'attente peut en plus exiger une preuve de travail avant qu'un numéro d'attente ne soit attribué. Le navigateur résout alors en arrière-plan une petite énigme cryptographique — invisible pour le visiteur et, à la difficulté par défaut, nettement inférieure à une seconde sur des appareils ordinaires. Pour une ferme de bots, la donne change : chaque inscription coûte le même travail de calcul, si bien que tirer des milliers de numéros devient proportionnellement coûteux au lieu d'être gratuit. La protection est désactivée par défaut et s'active par salle d'attente dans l'administration ADITUS ; la difficulté est réglable (de 8 à 24 bits, 15 par défaut — chaque bit supplémentaire double le travail). La page de salle d'attente hébergée résout l'énigme automatiquement ; rien ne change pour l'intégration de la boutique.

Une conséquence assumée : tant que la protection est active, le passage silencieux en dessous du rythme de redirection est désactivé — chaque visiteur traverse la salle d'attente, car c'est seulement là que la preuve de travail est fournie. Et une mise en perspective : la preuve de travail protège l'attribution des numéros d'attente contre l'inscription en masse. C'est une brique parmi d'autres contre les acheteurs automatisés, pas une défense anti-bot complète — combinez-la au besoin avec des mesures dans la boutique elle-même (par ex. des limites d'achat).

Seules les intégrations sur mesure qui appellent directement l'API de la file doivent résoudre l'énigme elles-mêmes. Le déroulement : récupérer un challenge, trouver un nonce dont le hash SHA-256 du challenge plus le nonce commence par le nombre requis de bits nuls, et soumettre les deux avec la requête d'inscription. Les challenges sont signés et valables cinq minutes ; leur réutilisation est en outre bloquée par instance :

Déroulement de la preuve de travail pour les intégrations sur mesure
// 1. Challenge holen (nur relevant, wenn PoW für die Queue aktiv ist)
GET https://developers.aditus.com/queue/<slug>/pow
// -> { queue, enabled: true, challenge, bits, expiresInSeconds: 300,
//      algorithm: "sha256" }

// 2. Nonce suchen: SHA-256(challenge + "." + nonce) muss mit <bits>
//    Null-Bits beginnen. Im Browser per WebCrypto — bei der
//    Standard-Schwierigkeit deutlich unter einer Sekunde.

// 3. Beitritt mit Lösung
POST https://developers.aditus.com/queue/<slug>/join
{ "pow": { "challenge": "…", "nonce": "…" } }

// Ohne oder mit ungültiger Lösung antwortet /join mit
// 428 Precondition Required — und liefert im Fehlerkörper direkt eine
// frische Challenge mit, sodass kein zweiter Abruf nötig ist.

Exploitation : ouvertures planifiées avec tirage équitable

Pour les ouvertures de ventes annoncées, une salle d'attente peut recevoir une heure d'ouverture fixe. Les visiteurs arrivés en avance se retrouvent dans une pré-file : la page de salle d'attente affiche un compte à rebours jusqu'à l'ouverture, personne n'est encore redirigé. À l'heure d'ouverture se produit l'étape décisive — l'ordre de redirection parmi toutes les personnes en attente à ce moment-là est tiré équitablement au sort. Arriver trois heures en avance n'apporte donc aucun avantage par rapport à trois minutes ; les marathons de rechargement et les onglets campés perdent tout leur intérêt. Quiconque rejoint après l'ouverture se place derrière le groupe tiré au sort, dans l'ordre d'arrivée normal.

Le tirage est une permutation mathématique sur les numéros d'attente attribués avant l'ouverture — chaque numéro reçoit exactement une position, aucun n'est perdu, aucun n'apparaît deux fois, et l'attribution n'est pas prévisible à partir de l'ordre d'inscription. Modifier l'heure d'ouverture dans l'administration réarme le tirage ; rien ne change pour l'intégration de la boutique ni pour l'API.

Exploitation : détection d'abandon

Tous ceux qui tirent un numéro d'attente ne restent pas. Les onglets fermés et les navigateurs abandonnés laissent sinon des trous : la fenêtre de redirection passe sur des numéros qui n'appartiennent plus à personne, et le débit réel tombe sous le rythme configuré. Avec la détection d'abandon activée, la page de salle d'attente hébergée signale sa présence par un heartbeat régulier. Si un numéro reste silencieux plus longtemps que le délai de grâce configuré (de 60 à 3600 secondes, 180 par défaut), il est considéré comme abandonné — et la fenêtre de redirection avance d'autant plus vite, de sorte que les places libérées reviennent aux visiteurs qui attendent réellement encore.

La détection est volontairement indulgente : un visiteur de retour dont le numéro avait été compté comme abandonné, mais qui se trouve déjà dans la fenêtre de redirection, est redirigé normalement — le heartbeat ne fait qu'accélérer, il ne révoque jamais une redirection. Les intégrations sur mesure qui construisent leur propre page d'attente envoient le même signal via POST /queue/<slug>/heartbeat (corps JSON avec le numéro d'attente, recommandé toutes les 60 secondes).

Exploitation : codes de contournement VIP

Presse, partenaires, contingents de fan-clubs : certains visiteurs ne devraient jamais voir de salle d'attente. Pour eux, des codes de contournement peuvent être créés par salle d'attente dans l'administration ADITUS — chacun avec un libellé, une limite d'utilisation optionnelle et une date d'expiration optionnelle, chacun désactivable ou supprimable à tout moment. Un code se partage sous forme de simple lien : /queue/<slug>/enter?code=… redirige directement vers la boutique avec un token d'accès valide, en contournant toute la file. Les intégrations sur mesure peuvent au contraire utiliser les codes via POST /queue/<slug>/bypass et recevoir le token en JSON.

Deux propriétés de sécurité assumées : un code invalide sur le lien gateway retombe en silence sur le parcours normal — de l'extérieur, impossible de savoir si un code a jamais existé. Et la route JSON répond de manière identique pour les codes invalides, expirés, épuisés et désactivés ; il n'existe donc aucun oracle pour deviner les codes. Les redirections par contournement sont marquées comme telles dans le token et ne consomment pas de places de redirection régulières.

Détails techniques

Les sections suivantes ne sont pas nécessaires à l'intégration — la balise de script ci-dessus est complète. Elles documentent le fonctionnement interne pour l'évaluation technique et pour les boutiques qui souhaitent vérifier en plus la redirection dans leur propre backend.

Fonctionnement de la redirection

Chaque visiteur reçoit un numéro d'attente séquentiel via un unique incrément atomique en base de données. La redirection progresse en continu : le numéro actuellement redirigé se calcule comme base + rythme × minutes écoulées. L'interrogation du statut est en lecture seule et ne sollicite pas la base de données à chaque requête. Il n'y a aucun état par visiteur sur le serveur, aucune tâche cron et aucun minuteur — le service de file ne peut pas devenir lui-même un goulot d'étranglement sous charge. Mettre une file en pause arrête à la fois la redirection et l'attribution de nouveaux numéros ; les changements de rythme prennent effet en continu et le numéro redirigé ne recule jamais.

Équité : strictement dans l'ordre d'arrivée

La redirection se fait strictement dans l'ordre d'arrivée (First come, first served) : l'incrément atomique fixe la position de chaque visiteur au moment de l'inscription, et les positions ne changent plus jamais ensuite. Il n'y a volontairement aucune loterie, aucune sélection aléatoire et aucune voie prioritaire — en situation de rareté, l'ordre d'arrivée est le seul classement que les visiteurs acceptent comme équitable, et le seul qui ne peut être manipulé. Le resquillage est techniquement exclu à deux niveaux : les numéros d'attente ne font que croître, et la vérification de redirection compare le numéro du visiteur au numéro actuellement redirigé côté serveur — le token d'accès n'est délivré qu'une fois cette vérification réussie, signé avec le secret de la file. Un visiteur ne peut pas revendiquer une meilleure position, et un token falsifié échoue à la vérification de signature. Les exploitants qui ont besoin de flux distincts — par exemple une salle d'attente par événement ou par vente — font tourner plusieurs salles d'attente indépendantes, chacune avec son propre slug, son secret, son rythme et sa configuration.

Architecture sous charge : chiffres mesurés

L'objectif de conception découle directement de la logique de redirection ci-dessus : comme le numéro redirigé se déduit du temps écoulé et que la vérification de statut ne lit aucun état par visiteur, la quasi-totalité du trafic visiteur est du calcul sans état. N'importe quelle instance peut répondre à n'importe quelle requête, les instances ne partagent rien d'autre que la base de données, et la plateforme ajoute automatiquement des instances sous charge. L'unique écriture en base de données par visiteur — l'incrément atomique à l'inscription — est le seul point de sérialisation, et il survient exactement une fois par visiteur, pas à chaque interrogation. Les chiffres ci-dessous proviennent du runner de tests de charge intégré décrit plus haut, mesurés via le endpoint HTTPS public contre une seule instance du service de file ; le profil mix combine inscription et interrogation du statut dans la proportion du parcours visiteur réel :

ExécutionRésultat
mix · 10 req/s · 30 sLatence p50 7,6 ms · p95 12,0 ms · taux d'erreur 0 %
mix · 25 req/s · 60 sLatence p50 7,3 ms · p95 11,4 ms · taux d'erreur 0 %
mix · 50 req/s · 45 sLatence p50 6,7 ms · p95 11,0 ms · taux d'erreur 0 %
status · 50 req/s · 45 sLatence p50 6,4 ms · p95 8,9 ms · taux d'erreur 0 %

Mesuré en juillet 2026 avec le chemin de code de production ; chaque exécution s'est terminée sans erreur et avec une latence médiane à un chiffre. Une seule instance encaisse cinquante requêtes par seconde — plusieurs milliers de visiteurs en attente interrogeant à l'intervalle recommandé — sans effort apparent ; au-delà, des instances supplémentaires prennent le relais. Cette mise à l'échelle n'est pas une boîte noire : chaque instance en cours d'exécution se signale en continu avec des métriques en direct — CPU, mémoire, débit de requêtes — consultables à tout moment dans l'administration ADITUS. On voit ainsi de façon transparente combien d'instances portent une ouverture des ventes et quelle réserve il reste. Des tests de charge planifiés revalident ces chiffres en continu contre le système de production, et une exécution nettement en retrait de ses prédécesseures est signalée automatiquement.

Endpoints

Dix endpoints, aucune authentification pour les visiteurs, CORS restreint aux domaines configurés par file. La page de salle d'attente hébergée utilise exactement cette API — elle peut aussi être pilotée directement pour une expérience d'attente entièrement sur mesure.

EndpointCe qu'il fait
GET /queue/<slug>Page de salle d'attente hébergée : demande un numéro, interroge le statut et redirige automatiquement le visiteur une fois autorisé.
POST /queue/<slug>/joinAttribuer un numéro d'attente (le seul accès en écriture du parcours visiteur). 423 tant que la file est en pause.
GET /queue/<slug>/status?number=NInterroger le statut de redirection d'un numéro — en lecture seule, avec un en-tête Retry-After. 404 pour les numéros jamais émis.
POST /queue/<slug>/tokenÉchanger un numéro autorisé contre un JWT HS256 signé. 425 tant que le numéro n'est pas encore autorisé ; 404 pour les numéros jamais émis.
GET /queue/<slug>/enterPoint d'entrée gateway : publié à la place de l'URL de la boutique. Redirige directement vers l'URL cible configurée (avec token d'accès) tant que de la capacité est disponible ; sinon vers la salle d'attente. Nécessite une URL cible configurée. Accepte ?code=… pour les codes VIP : un code valide contourne entièrement la file, un code invalide retombe sur le parcours normal sans aucun indice.
GET /queue/<slug>/embed.jsScript d'intégration côté boutique : laisse entrer les visiteurs en silence tant que personne n'attend ; dès qu'une file s'est formée, il dirige les visiteurs sans laissez-passer valide vers la salle d'attente et les ramène exactement à la page d'origine.
GET /queue/<slug>/verify?token=…Vérification de token côté serveur utilisée par le script d'intégration : valide la signature, l'audience et l'expiration d'un token d'accès.
GET /queue/<slug>/infoInfos publiques de la file : statut actif, numéro actuellement autorisé et nombre de personnes en attente.
POST /queue/<slug>/heartbeatSignal de présence pour la détection d'abandon optionnelle : la page de salle d'attente signale qu'un numéro est toujours présent. Silencieusement accepté tant que la détection est désactivée.
POST /queue/<slug>/bypassUtiliser un code VIP via JSON : renvoie un token d'accès et l'URL cible. Les codes invalides, expirés, épuisés et désactivés renvoient tous le même 404 — aucun oracle pour deviner les codes.
GET /queue/<slug>/powChallenge de preuve de travail pour la protection anti-bot optionnelle : renvoie enabled: false tant que la protection est désactivée ; sinon un challenge signé dont /join attend la résolution.
GET /queue/healthzHealth check public pour la supervision de disponibilité : répond sans authentification et sans accès à la base de données. Volontairement exclu des métriques d'instance, afin que les pings de supervision ne faussent jamais l'image du trafic.

1. Demander un numéro d'attente

join.ts
// Wartenummer anfordern (einziger Schreibzugriff im Besucherpfad).
const res = await fetch("https://developers.aditus.com/queue/<slug>/join", {
  method: "POST",
});
const ticket: {
  queue: string;              // Queue-Slug
  name: string;               // Anzeigename des Warteraums
  number: number;             // vergebene Wartenummer
  serving: number;            // bis zu dieser Nummer wird weitergeleitet
  ahead: number;              // Anzahl Nummern vor dieser
  admitted: boolean;          // true -> sofort weiter zu /token
  estimatedWaitSeconds: number;
  retryAfterSeconds: number;  // empfohlenes Polling-Intervall
} = await res.json();
// 423 Locked -> der Warteraum ist pausiert (keine Weiterleitung, keine neuen Nummern).

2. Interroger le statut

status.ts
// Statusabfrage — rein lesend, beliebig oft wiederholbar.
// Der Server sendet zusätzlich einen Retry-After-Header.
const res = await fetch(
  "https://developers.aditus.com/queue/<slug>/status?number=" + ticket.number,
);
const status: {
  queue: string;
  name: string;
  active: boolean;            // false -> Weiterleitung pausiert
  number: number;
  serving: number;
  ahead: number;
  admitted: boolean;
  estimatedWaitSeconds: number;
  retryAfterSeconds: number;
} = await res.json();

if (status.admitted) {
  // -> Token abholen und zum Shop weiterleiten
}

3. Récupérer le token d'accès

token.ts
// Sobald admitted=true: Zugriffs-Token abholen.
const res = await fetch("https://developers.aditus.com/queue/<slug>/token", {
  method: "POST",
  headers: { "Content-Type": "application/json" },
  body: JSON.stringify({ number: ticket.number }),
});
// 425 Too Early -> die Nummer ist noch nicht zur Weiterleitung freigegeben.
const grant: {
  queue: string;
  number: number;
  token: string;              // signierter HS256-JWT
  tokenType: "JWT";
  expiresInSeconds: number;   // Standard: 600 s
  targetUrl: string | null;   // konfiguriertes Weiterleitungsziel
} = await res.json();

// Weiterleitung übernimmt die gehostete Warteraum-Seite automatisch:
// targetUrl + "?aditus_queue_token=" + grant.token

Optionnel : vérifier le token dans votre propre backend

L'intégration par balise de script est complète en soi. Les boutiques qui maîtrisent leur backend peuvent y vérifier en plus le token d'accès : c'est un JWT HS256 standard, vérifiable hors ligne avec le secret partagé — aucun rappel vers la file, aucune latence supplémentaire. Le secret est généré à la création de la file, affiché une seule fois, et peut être renouvelé à tout moment. Claims : iss vaut toujours aditus-queue, aud est le slug de la file, qnr est le numéro d'attente redirigé, exp limite la validité (10 minutes par défaut). Remarque : le passage silencieux en dessous du rythme de redirection ne produit pas de token — un backend qui exige impérativement un token devrait envoyer les visiteurs qui n'en ont pas vers la salle d'attente, laquelle délivre alors immédiatement un token lorsque personne n'attend.

verify.ts
// ZIELSYSTEM (dein Shop / deine Seite): Token prüfen — Standard-JWT (HS256).
// Das Secret erhältst du einmalig von ADITUS beim Einrichten des Warteraums.
import jwt from "jsonwebtoken";

const payload = jwt.verify(token, process.env.ADITUS_QUEUE_SECRET!, {
  algorithms: ["HS256"],
  issuer: "aditus-queue",     // iss ist immer aditus-queue
  audience: "<slug>",         // aud ist der Queue-Slug deines Warteraums
}) as { qnr: number; iat: number; exp: number };

// payload.qnr = die weitergeleitete Wartenummer.
// Gültiger Token -> Besucher passieren lassen (z. B. Cookie setzen).
// Fehlender/ungültiger Token -> zurück in den Warteraum:
//   https://developers.aditus.com/queue/<slug>

La sécurité en un coup d'œil

Les mécanismes de sécurité sont décrits ci-dessus là où ils s'insèrent dans le déroulement ; cette section les rassemble. Tokens signés : les tokens d'accès sont des JWT HS256, signés avec un secret propre à chaque file, affiché une seule fois et renouvelable à tout moment ; le lien d'audience (slug de la file) et une courte validité (10 minutes par défaut) limitent la valeur d'un token intercepté. Protection anti-bot : la vérification optionnelle par preuve de travail rend l'inscription en masse depuis des fermes de bots proportionnellement coûteuse ; les challenges sont signés en HMAC et expirent au bout de cinq minutes ; une protection best-effort par instance bloque en outre la réutilisation d'un challenge déjà consommé — le véritable facteur de coût est le travail de hachage lui-même. Redirections : les URL de retour sont validées côté serveur par rapport aux domaines configurés par file — la salle d'attente ne devient jamais une redirection ouverte. Surface d'API : les endpoints visiteurs ne portent aucune donnée d'authentification, le CORS est restreint par file, l'accès admin utilise des clés d'API liées chacune à une seule salle d'attente, stockées uniquement sous forme de hash, incapables de gérer d'autres clés et laissant une trace d'audit. Pics de trafic : l'architecture sans état absorbe la charge par conception — n'importe quelle instance répond à n'importe quelle requête, et la plateforme met les instances à l'échelle automatiquement ; le filtrage DDoS au niveau réseau est assuré par la plateforme d'hébergement en amont du service.

Cas de défaillance : que se passe-t-il quand quelque chose tombe en panne

Une salle d'attente se tient devant le chiffre d'affaires — son comportement en cas de panne compte autant que son fonctionnement nominal.

  • Service de file injoignable (variante balise de script) : le script bascule en défaillance ouverte — la boutique reste pleinement utilisable. Une panne de la salle d'attente ne bloque jamais la boutique.
  • Service de file injoignable (variante gateway) : les nouvelles entrées sont mises en pause ; les visiteurs déjà redirigés sont sur la boutique et poursuivent sans être affectés.
  • Perte d'une seule instance : aucun visiteur ne le remarque. Aucun état par visiteur ne réside sur une instance — chaque instance répond à chaque requête, la base de données partagée est le seul composant avec état.
  • Rafraîchissement du navigateur : le numéro d'attente est conservé dans la session du navigateur — un rechargement retrouve la même position, la place dans la file n'est jamais perdue.
  • Le visiteur efface les cookies ou le stockage du navigateur : la position est volontairement non récupérable — le visiteur tire un nouveau numéro en fin de file. Toute autre solution ouvrirait la porte à la fraude sur les positions.
  • Salle d'attente en pause : l'inscription et la redirection s'arrêtent avec un signal clair (HTTP 423) et un message explicatif dans la salle d'attente — aucune erreur silencieuse.
  • Le health check de la boutique échoue (rythme automatique) : le rythme gèle d'abord, puis tombe au minimum configuré — un health check injoignable n'ouvre jamais davantage les portes.

Positionnement face aux solutions de salle d'attente spécialisées

ADITUS-Queue traite les mêmes problématiques techniques que les produits d'entreprise spécialisés de salle d'attente virtuelle. Le tableau met en regard les capacités à l'aune desquelles ces produits sont jugés et la façon dont ADITUS-Queue les couvre — y compris une omission assumée.

CapacitéDans ADITUS-Queue
ÉquitéFCFS strict via incrément atomique ; resquillage techniquement exclu.
Fail-openAvec l'intégration par balise de script, une panne de la salle d'attente ne bloque jamais l'application protégée ; les visiteurs déjà redirigés ne sont affectés dans aucune variante.
Application au niveau de l'edgeVérification de token hors ligne dans Nginx, Caddy, Cloudflare, CloudFront — aucune latence ajoutée.
Protection anti-botPreuve de travail optionnelle par file, invisible pour les vrais navigateurs.
Performances prouvéesChiffres mesurés publiés, revalidés en continu par des tests de charge planifiés en production.
Rythme de redirection adaptatifRythme autorégulé piloté par le health check propre de l'application protégée.
API-firstChaque fonction visiteur et admin est un endpoint REST documenté.
Voies prioritaires / VIPVolontairement non proposées — l'ordre d'arrivée strict est la promesse d'équité. Les publics distincts fonctionnent comme des salles d'attente distinctes.

Administration par clé d'API

Tout ce que l'administration ADITUS peut faire pour une seule salle d'attente — ajuster le rythme de redirection, mettre en pause, modifier la configuration — est aussi accessible aux machines. L'accès se fait via une clé d'API préfixée par qak_, envoyée comme Bearer token ; chaque clé est créée pour exactement une salle d'attente et ne peut lire et modifier que celle-ci. Les clés sont créées et révoquées dans l'administration, affichées une seule fois et stockées uniquement sous forme de hash. Le cas d'usage typique est un runbook d'ouverture des ventes : une tâche planifiée relève le rythme de redirection juste avant le début, un script met la file en pause en cas d'urgence, la supervision lit la configuration actuelle. Trois garde-fous s'appliquent : une clé n'atteint jamais d'autres salles d'attente ni les fonctions d'administration globales (tests de charge, planifications, instances) — ces requêtes sont rejetées côté serveur ; la gestion des clés elle-même est volontairement impossible avec une clé — une clé fuitée ne peut jamais créer ni lister d'autres clés — ; et chaque modification effectuée avec une clé est enregistrée dans le journal d'audit sous le nom de la clé et de sa salle d'attente.

Exemples avec curl
# Konfiguration des zugeordneten Warteraums lesen. Jeder Key ist an genau
# einen Warteraum gebunden — die Liste enthält daher höchstens diesen einen
# Eintrag; andere Warteräume und globale Verwaltungsfunktionen sind mit
# einem Key nicht erreichbar.
curl -H "Authorization: Bearer qak_…" \
  https://developers.aditus.com/api/admin/queue/sites

# Weiterleitungsrate im laufenden Betrieb anheben: Lesen -> Feld ändern -> Schreiben.
# PATCH erwartet die vollständige Konfiguration (ohne slug); unbekannte
# Felder wie id oder Zeitstempel werden serverseitig ignoriert.
KEY="qak_…"; BASE="https://developers.aditus.com/api/admin/queue"
SITE=$(curl -s -H "Authorization: Bearer $KEY" "$BASE/sites" \
  | jq '.sites[0]')
echo "$SITE" | jq '.ratePerMinute = 300' | curl -s -X PATCH \
  -H "Authorization: Bearer $KEY" -H "Content-Type: application/json" \
  -d @- "$BASE/sites/$(echo "$SITE" | jq -r .id)"

# Zugeordneten Warteraum pausieren (keine Weiterleitung, keine neuen Nummern):
# active = false
echo "$SITE" | jq '.active = false' | curl -s -X PATCH \
  -H "Authorization: Bearer $KEY" -H "Content-Type: application/json" \
  -d @- "$BASE/sites/$(echo "$SITE" | jq -r .id)"
Planifié via GitHub Actions
# .github/workflows/onsale.yml — Weiterleitungsrate zum Vorverkaufsstart anheben.
# Den API-Key als Repository-Secret ADITUS_QUEUE_API_KEY hinterlegen. Der Key
# ist an den Warteraum des Vorverkaufs gebunden — mehr kann er nicht.
name: Weiterleitungsrate zum On-Sale anheben
on:
  schedule:
    - cron: "55 8 14 3 *"   # 14. März, 08:55 UTC — kurz vor dem On-Sale
  workflow_dispatch: {}

jobs:
  raise-rate:
    runs-on: ubuntu-latest
    steps:
      - name: Rate auf 300/min anheben
        env:
          KEY: ${{ secrets.ADITUS_QUEUE_API_KEY }}
        run: |
          BASE="https://developers.aditus.com/api/admin/queue"
          # Der Key sieht nur seinen gebundenen Warteraum — .sites[0] genügt.
          SITE=$(curl -sf -H "Authorization: Bearer $KEY" "$BASE/sites" \
            | jq '.sites[0]')
          echo "$SITE" | jq '.ratePerMinute = 300' \
            | curl -sf -X PATCH \
              -H "Authorization: Bearer $KEY" \
              -H "Content-Type: application/json" \
              -d @- "$BASE/sites/$(echo "$SITE" | jq -r .id)"