LB'XMB.FR
LB'XMB.FR LogoLB'XMB.FR
GuidesGuidesResourcesResourcesForumForumWorkshopWorkshopSupportSupportShopShopToolsToolsDownloadDownloadDonateDonate

Changelogs

Historique des évolutions LB'XMB.FR (site, bot Discord, forum, boutique, intégrations). Cette page est synchronisée avec le document interne de récapitulatif.

2026-08-18 13:05 — Concours Discord d’ajout de ressources

### Contexte / problème

Mettre en place un concours public : classement des ajouts de ressources, 10 € au premier, reset au 5 septembre puis chaque lundi, mention du gagnant, bouton pour voir qui a ajouté quoi.

### Changements appliqués

### Impact visible / technique

### Fichiers touchés

bot-site/src/lib/siteDb.js, bot-site/src/lib/resourceContestStats.js, bot-site/src/index.js, bot-public/src/lib/resourceContest.js, bot-public/src/events/client/ready.js, bot-public/src/events/interaction/interactionCreate.js, bot-public/src/lib/internalHttpServer.js, bot-public/src/handlers/verification/webVerificationQueue.js

  • Container Discord live dans le salon 1539198613014716446 (classement + fin de période Discord timestamps).
  • Compteur alimenté par resources.date_creation (MariaDB) : requête partagée bot-site/src/lib/resourceContestStats.js (HTTP GET /resource-contest/stats + import direct depuis bot-public).
  • Première manche : 18 août 00:00 → 5 septembre 2026 23:59 (Europe/Paris), puis cycles hebdomadaires le lundi 00:00.
  • À la clôture : message qui mentionne le gagnant (10 €) et reset du classement à 0.
  • Bouton « Voir qui ajoute quoi » (éphémère, filtre par participant, pagination) + lien « Ajouter une ressource ».
  • Rafraîchissement auto ~20 s et à chaque site_new_resource.
  • Panneau unique édité en place (pas de spam). Mentions du classement sans ping ; ping uniquement à l’annonce du gagnant.
  • Intervalle configurable : RESOURCE_CONTEST_INTERVAL_WEEKS (1 = chaque lundi, 2 = un lundi sur deux), RESOURCE_CONTEST_PRIZE_EUR, RESOURCE_CONTEST_CHANNEL_ID.
2026-08-14 19:30 — Profil, pages, vocaux, membres

### 1. Profil : bannière et avatar

#### Contexte / problème

Header sticky z-10 recouvrait l’avatar (-mt-10 dans le flux scrollable).

#### Changements

Sticky = poignée seulement. Bannière + avatar dans le même flux, avatar -mt-10 relative z-[1].

#### Fichiers

ForumGroupServerProfileCard.tsx

### 2. Accueil mobile + vocaux mis en avant

#### Contexte / problème

Pas de retour mobile. Édition Accueil peu claire pour vocal/conférence.

#### Changements

#### Fichiers

ForumGroupHomeView.tsx, forum-group-home.ts, home/route.ts, ForumGroupCommunityPanel.tsx

### 3. Pages : défaut, ACL, salons, rôles, settings mobile

#### Contexte / problème

0 pages, create channel ignore la page, roleIds ne filtraient rien. Settings pages illisible sur mobile.

#### Changements

#### Fichiers

2026-08-14 17:10 — Profil, membres, Accueil, pages, événements

### 1. Profil serveur

#### Contexte / problème

Boutons petits en wrap ; tout le sheet scrollait d’un bloc.

#### Changements

Bannière sticky. Body scroll. Actions empilées pleine largeur (Signaler, Avis, Quitter). Formulaire d’avis sous le bouton.

#### Fichiers

ForumGroupServerProfileCard.tsx

### 2. Liste membres

#### Contexte / problème

3e carte détachée, breakpoints md/lg incohérents.

#### Changements

Membres collés au chat (border-l, md:flex). Drawer md:hidden overlay uniquement la carte chat.

#### Fichiers

ForumGroupCommunityPanel.tsx

### 3. Topic → salon en bas

#### Contexte / problème

PATCH recalé sort_order dès que categoryId était envoyé.

2026-08-14 16:20 — Profil serveur : sheet bas + icône

### Contexte / problème

Le profil s’ouvrait en dialog centré. Seul le nom du serveur était cliquable, pas l’icône.

### Changements

### Impact visible / technique

Geste proche de Discord mobile. Overlay + slide 300 ms.

### Fichiers

ForumGroupServerProfileCard.tsx, ForumGroupCommunityPanel.tsx

#### Déploiement

BUILD_ID H5lBbFKcTrDxcGeUhyHi_. web-prod redémarré (5 workers online).

  • Panneau en Sheet side="bottom" : glisse du bas vers le haut (coins arrondis, poignée, overlay).
  • Clic sur l’icône du serveur (header liste salons) ouvre aussi le profil.
2026-08-14 15:44 — Profil serveur, salons, événements, markdown

### 1. Profil serveur (clic nom)

#### Contexte / problème

Clic sur le nom du serveur n’ouvrait qu’un petit dialog. Pas d’avis, d’emojis, ni de compteurs.

#### Changements

#### Impact visible / technique

Panneau lecture style Discord. createdAt / creatorPseudo exposés dans GroupInfo.

#### Fichiers

ForumGroupServerProfileCard.tsx, ForumGroupCommunityPanel.tsx, forum-group-reviews.ts, reviews/route.ts, forum-group-selfhost.ts

### 2. Long-press salon = menu Modifier

#### Contexte / problème

Sur tactile, draggable lançait le drag HTML5 au lieu du menu contextuel.

#### Changements

#### Fichiers

ForumGroupCommunityPanel.tsx

### 3. Icônes forum / membres

#### Contexte / problème

2026-08-14 12:49 — Membres, panneau user, logs, invitations, picker

### 1. Liste membres

#### Contexte / problème

Header « Fondateur — 1 » puis le nom de rôle répété sur chaque ligne. Groupe « Default » pour les rôles non hoistés.

#### Changements

#### Fichiers

ForumRoleLabel.tsx, ForumGroupCommunityPanel.tsx

### 2. Noms de salons

#### Contexte / problème

TranslatedText traduisait les noms de salons.

#### Changements

Affichage brut {ch.name} (texte + vocal).

#### Fichiers

ForumGroupCommunityPanel.tsx

### 3. Carte utilisateur rail

#### Contexte / problème

Barre user sous les salons, pas dans la liste des serveurs. Mute/casque seulement en vocal.

#### Changements

2026-08-14 11:48 — Mentions, composer, salons scroll, dossiers

### 1. Highlight mention / réponse

#### Contexte / problème

Pas de fond Discord-like quand on est mentionné. Les réponses n’étaient pas persistées.

#### Changements

#### Impact visible / technique

Les messages qui te concernent se voient tout de suite.

#### Fichiers

forum-voice.ts, messages/route.ts, ForumGroupCommunityPanel.tsx, MessageLinkEmbeds.tsx, MessageReplyPreview.tsx

### 2. Micro / envoi

#### Contexte / problème

Send lucide toujours visible ; pas de notes vocales dans les salons.

#### Changements

#### Impact visible / technique

Même geste que les MP : micro si rien n’est tapé, envoi vocal au relâchement.

#### Fichiers

MessageComposerBar.tsx, ForumGroupCommunityPanel.tsx, VoiceMessagePlayer.tsx

2026-08-14 11:28 — Réactions, tag, plaque, settings

### 1. Réactions (annonces / actualités)

#### Contexte / problème

Bouton SmilePlus invisible hors hover (opacity-0) : rien au tactile. Cœur Discord -# 👁️ · ❤️ n en texte inerte. Compteur JSON ne montait pas tout de suite.

#### Changements

#### Impact visible / technique

Réagir depuis le mobile ; le compteur +1 tout de suite ; le chip apparaît.

#### Fichiers

MessageReactions.tsx, ForumGroupCommunityPanel.tsx, messages/[messageId]/reactions/route.ts

### 2. Tag du serveur — onglet + styles

#### Contexte / problème

Tag mélangé au profil serveur, style argent unique.

#### Changements

#### Impact visible / technique

Onglet dédié ; chips colorés selon le métal/gemme choisi.

#### Fichiers

forum-server-tag-style.ts, forum-server-tag.ts, forum-group-permissions.ts, ServerTagBadge.tsx, ForumGroupSettingsModal.tsx, groups/[slug]/route.ts, summary/route.ts, invite-domains/[host]/route.ts, me/primary-tag/route.ts

2026-08-14 09:35 — Lot D : voix publique unique, snowflake dév-test, settings UX, bans/logs

### Contexte / problème

Lot D (hors overwrite tests déjà corrects) : lobby vocal social listait tous les group_id IS NULL ; snowflake Discord dev-test obsolète ; DELETE messages ignorait les overwrites MANAGE_MESSAGES ; settings salons (cats puis salons), overflow mobile, menu membres clipé, rôles mobile, logs EN, bans sans durée/notify.

### Changements

### Impact visible / technique

Lobby vocal public = 2 salons officiels. Overwrite salon peut refuser la suppression de messages. Settings scrollables sur mobile. Bans temporaires + notification optionnelle.

### Fichiers

forum-voice-social-migrate.ts, api/forum/voice/channels/route.ts, ForumVoiceLobby.tsx, community-bridge-map.ts, community-bridge.ts, forum-official-server.ts, forum-group-permissions.ts, forum-group-permissions.resolve.test.ts, forum-group-audit-labels.ts, messages/[messageId]/route.ts, channels/[channelId]/route.ts, roles/[roleId]/route.ts, bans/route.ts, join/route.ts, invites/[code]/route.ts, ticket-notifications.ts, dropdown-menu.tsx, ForumGroupSettingsModal.tsx, ForumGroupRolesPanel.tsx, ForumGroupCommunityPanel.tsx, docs/RECAP-…

2026-08-14 09:20 — Lot B : expressions (ACL view/use, 4 Mio, trim 10 s, picker, tokens)

### 1. ACL voir / utiliser à l’ajout

#### Contexte / problème

Un seul multi-select roleIds (canView+canUse). Il fallait séparer « voir » et « utiliser » dès le POST.

#### Changements

#### Impact visible / technique

À la création, on peut restreindre la visibilité sans autoriser l’usage, et inversement.

#### Fichiers

ForumGroupExpressionsPanel.tsx, expressions/route.ts

### 2. Limites 4 Mio + trim audio 10 s

#### Contexte / problème

Plafonds trop bas (512 Ko / 1 Mio / 2 Mio) ; pas de coupe à 10 s pour le soundboard.

#### Changements

#### Impact visible / technique

Images plus lourdes acceptées. Un son trop long doit être découpé avant envoi.

2026-08-14 07:45 — Build CSS : exclusion scan Tailwind (.next / ptb)

### Contexte / problème

bun run build cassait sur globals.css (Missed semicolon) : Oxide scannait .next / copies ptb et générait des utilitaires binaires corrompus.

### Changements

@source not pour .next, .next-staging, ptb-web, web-old-*, forum-expression-tokens.ts.

### Impact visible / technique

Le build PostCSS Tailwind reprend.

### Fichiers

web/src/app/globals.css

2026-08-14 07:30 — Lot A (fin) : rôles vocal, invite vanity, modal membres rôle

### Contexte / problème

Lot A incomplet : CTA invite vanity sans isMember, couleurs de rôle absentes du vocal, ajout de membres au rôle encore en checkboxes inline.

### Changements

### Impact visible / technique

Pseudos du vocal et du chat suivent la couleur du rôle hoisté. Invitation déjà membre → « Voir le serveur » aussi sur domaine vanity.

### Fichiers

invite-domains/[host]/route.ts, ForumGroupRolesPanel.tsx, ForumVoiceSession.tsx, ForumVoiceCallStage.tsx, ForumVoiceSidebar.tsx, ForumRoleLabel.tsx, members/route.ts, ForumGroupCommunityPanel.tsx, use-forum-social.ts, display-roles/route.ts

  • GET invite-domains/[host] : isMember si session (bouton Voir le serveur vs Rejoindre).
  • Modal « Ajouter des membres » (recherche + multi-select) dans ForumGroupRolesPanel.
  • Vocal : displayRole hoisté via /api/forum/voice/channels/[id]/display-roles ; pseudos colorés (tuiles + rail).
2026-08-14 07:30 — Lot C : analyse serveur Recharts + tracking

### Contexte / problème

Onglet « Analyse du serveur » était un stub. Pas de lectures, vocal, ni départs historisés.

### Changements

### Impact visible / technique

Graphe d’activité dans Paramètres → Analyse. Lectures / vocal / départs à 0 sur l’historique passé, puis remplis à partir de maintenant.

### Fichiers

forum-group-analytics.ts, analytics/route.ts, channels/[channelId]/read/route.ts, ForumGroupAnalyticsPanel.tsx, ForumGroupSettingsModal.tsx, ForumGroupCommunityPanel.tsx, token/route.ts, voice/.../leave/route.ts, leave/route.ts, members/[userId]/route.ts

  • Schéma : forum_group_channel_reads, forum_group_analytics_read_days, forum_group_voice_sessions.
  • GET /api/forum-social/groups/[slug]/analytics?days=7|14|30 : messages (backfill), lectures (ping), minutes vocal, joins (joined_at), leaves (member.leave / kick / ban).
  • Ping POST .../channels/[channelId]/read à l’ouverture d’un salon texte.
2026-08-13 21:23 — Bot GitHub starred : releases + push seulement

### Contexte / problème

bot-public pollait /repos/.../events sur les repos starringés (issues, PR, stars, wiki…). Bruit Discord + rate limit GitHub. updated_at changeait sans push.

### Changements

### Impact visible / technique

Salon starred : uniquement releases et vrais updates de repo. Quota GitHub : 1 liste starred / 15 min + 1 release uniquement si le repo a été poussé.

### Fichiers

bot-public/src/lib/notifications/githubStarred.js

  • Plus d’appel /events. Éligibilité : pushed_at, archive, rename (plus updated_at).
  • Si push : GET /releases/latest → embed release si nouvel id, sinon un embed « Mise à jour » vers les commits.
  • Premier passage : mémorise last_release_id sans poster.
  • ghFetch : 429 loggé (Retry-After, remaining), tick arrêté.
2026-08-13 21:00 — Deploy web-prod (saisie TipTap + import Rentry)

### Contexte / problème

Les correctifs saisie + onglet Rentry n’étaient pas encore en prod.

### Changements

### Impact visible / technique

Hard refresh sur /guides/ajouter : saisie stable + onglet « Importer un Rentry ».

### Fichiers

déploiement web-prod

  • bun run deploy:web-prod : build OK, pm2 restart web-prod.
2026-08-13 20:55 — Fix saisie TipTap (reset) + import Rentry

### Contexte / problème

1. En prod, chaque lettre dans l’éditeur de guides était effacée : TipTap v3 réapplique content / editorProps / Placeholder à chaque rendu parent (onUpdate → setState).

2. Demande d’un import Rentry à côté de l’onglet README GitHub.

### Changements

### Impact visible / technique

On peut taper dans /guides/ajouter sans perte. Nouvel onglet Rentry à côté de GitHub.

### Fichiers

GuideEditorWord.tsx, GuideRentryImportPanel.tsx, lib/rentry.ts, lib/guide-content-format.ts, api/guides/rentry-preview/route.ts, api/guides/create/route.ts, api/guides/[folder]/route.ts, guides/ajouter/page.tsx, guides/[folder]/page.tsx, GuidePayloadPreview.tsx, messages/{fr,en}.json

  • Éditeur isolé (GuideChapterTiptap) : contenu initial figé, extensions/editorProps stables, key = id d’étape (plus de setContent à la frappe).
  • Onglet Importer un Rentry : fetch URL (/api/raw puis scrape HTML → markdown), collage markdown en secours.
2026-08-13 20:41 — Deploy web-prod éditeur guides (saisie + barre d’insertion)

### Contexte / problème

Les correctifs saisie/UI étaient locaux ; le deploy précédent avait échoué (@tanstack/react-table v9). La prod restait sur l’ancienne page.

### Changements

### Impact visible / technique

/guides/ajouter en prod : espaces dans les titres d’étapes, saisie TipTap stable, barre d’insertion (Image, Question, Spoiler, Encadrés, Code, Tableau). Hard refresh recommandé.

### Fichiers

déploiement web-prod (pas de nouveau diff code)

  • bun run deploy:web-prod : build OK, swap .next-staging, pm2 restart web-prod.
  • BUILD_ID : UpSEnMVS2msfrWmvTZY_h.
2026-08-13 20:40 — Fix saisie éditeur guides + deploy prod

### Contexte / problème

En prod : pas d’espace dans les titres d’étapes (Espace = clic a11y), l’éditeur TipTap se reset à chaque frappe (useEffect sync trop large), nouvelle UI pas déployée (build précédent cassé).

### Changements

### Impact visible / technique

On peut écrire dans le guide et mettre des espaces dans les titres. La barre d’insertion se voit sans taper /.

### Fichiers

GuideEditorWord.tsx, docs/RECAP-…

  • stopPropagation sur l’input titre ; Espace/Entrée sur la ligne seulement hors champ.
  • Sync TipTap uniquement au changement d’étape.
  • Barre d’insertion toujours visible (Image, Question, Spoiler, Encadrés, Code, Tableau).
  • Deploy web-prod.
2026-08-13 20:20 — Éditeur de guides simple (slash, spoiler, choix)

### Contexte / problème

L’éditeur Word était trop lourd (grosse barre d’outils) et ne permettait pas les besoins tutoriels : image spoiler, questions à choix (ex. version Luma 3DS), formatage type Discord/GitHub.

### Changements

### Impact visible / technique

Création plus légère. Un guide peut adapter le contenu selon la réponse (11.00 / 7.00 / 14.50). Format JSON word inchangé (nœuds dans le doc TipTap). Import GitHub toujours en 2e onglet.

### Fichiers

guide-editor-nodes.ts, guide-editor-extensions.ts, guide-editor-extensions-react.ts, GuideEditorWord.tsx, GuideChapterView.tsx, nodes/Guide{Image,Callout,Choice}NodeView.tsx, GuideTranslationContext.tsx, guides/[folder]/page.tsx, guides/ajouter/page.tsx, globals.css, messages/{fr,en}.json

  • Barre Word remplacée par menu / + menu flottant (gras, lien, titres, spoiler).
  • Nœuds TipTap : image spoiler + légende, spoiler texte ||…||, encadré info/warning/danger, question/choix imbriqués.
2026-08-13 19:45 — Pin `@tanstack/react-table` v8 (build prod)

### Contexte / problème

deploy:web-prod échouait : Turbopack 14 erreurs sur data-table.tsx (getCoreRowModel, useReactTable, etc. absents). Le code dashboard est API v8 ; le paquet était en ^9.1.2.

### Changements

Pin @tanstack/react-table à ^8.21.3. bun install ; bun audit toujours 0 vuln.

### Impact visible / technique

Les exports v8 (useReactTable, getCoreRowModel, …) sont de nouveau présents. Le build dashboard tasks peut passer.

### Fichiers

web/package.json, web/bun.lock

2026-08-13 19:40 — bun audit : 10 vulns → 0

### Contexte / problème

bun audit dans web/ signalait 10 vulnérabilités (3 high, 6 moderate, 1 low). Les overrides/resolutions épinglaient encore des versions vulnérables (socket.io-parser 4.2.6, ip-address 10.1.x/10.2.0, nested hono 4.12.33, dompurify 3.4.12, nested nanoid 3.3.16).

### Changements

Overrides/resolutions montés : dompurify ^3.4.13, ip-address ^10.3.1, nanoid ^3.3.18, socket.io-parser ^4.2.7, hono ^4.13.2. Puis bun install (lockfile uniquement via ces pins). Pas de bun update --latest.

### Impact visible / technique

bun audit : No vulnerabilities found.

### Fichiers

web/package.json, web/bun.lock

2026-08-13 19:30 — Restauration écriture manuelle des guides

### Contexte / problème

La page /guides/ajouter ne proposait plus que l’import d’un README GitHub. Impossible d’écrire un guide soi-même (éditeur Word, chapitres / pages). L’édition ?edit= était ignorée. L’API create acceptait encore le format word.

### Changements

### Impact visible / technique

On peut à nouveau rédiger un guide avec plusieurs chapitres sans coller une URL GitHub. L’import README reste optionnel. L’édition des deux formats fonctionne.

### Fichiers

web/src/app/guides/ajouter/page.tsx, web/src/components/guides/GuideGithubImportPanel.tsx, web/src/app/api/guides/[folder]/route.ts, web/messages/{fr,en}.json

  • Page /guides/ajouter : deux modes — Écrire un guide (défaut, TipTap multi-chapitres) et Importer un README GitHub.
  • Restauration ?edit= : précharge Word ou README selon le format.
  • Panneau import extrait dans GuideGithubImportPanel.
  • PUT /api/guides/[folder] accepte github_readme ; GET renvoie github_url / owner / repo / branch / html_url.
2026-08-13 10:00 — Vague D App UX batch 18 : Éclipse, rail mobile DnD, profil avatar, translate A-Za-z

### Contexte

Vague D du plan App UX batch 18 : abonnement Éclipse (gate création serveur hébergé), DnD/dossiers rail mobile, UserProfilePopover avatar-only, traduction limitée aux runs [A-Za-z]+.

### Changements

#### 15. Éclipse subscription

#### 16. Mobile rail DnD + folders

#### 17. Profile only on avatar click

#### 18. Translate A-Za-z only

### Impact visible / technique

Éclipse achetable (Stripe) débloque la création de serveurs hébergés ; Premium legacy toujours OK. Rail mobile réordonnable par long-press. Profils moins « accidentels ». Traduction ignore accents/chiffres/symboles hors A–Z. Pas de déploiement.

### Fichiers

vip-group-create.ts, vip-tier.ts, api/vip/checkout, api/vip/activate, api/vip/status, api/forum-social/groups/route.ts, SiteAppDonatePanel.tsx, SiteAppServerRail.tsx, SiteAppServerRailList.tsx, SiteAppShell.tsx, vip-page-data.ts, VipPageSections.tsx, vip/page.tsx, messages/{fr,en}.json, role-styles.ts, dashboard/users/[id]/edit/page.tsx, ForumGroupCommunityPanel.tsx, libretranslate.ts, TranslatedText.tsx, docs/RECAP-…

2026-08-13 09:35 — Vague C App UX batch 18 : content_embed, forum Discord-like, settings regroupés, badges grades

### Contexte

Vague C du plan App UX batch 18 : embeds guides/ressources/boutique sur salons, vue forum style Discord, paramètres utilisateur regroupés, badges Fondateur/Admin/Modérateur uniquement.

### Changements

#### 11. content_embed guides/ressources/boutique

#### 12. Forum channel Discord-like

#### 13. User settings regroupés

#### 14. Grade badges profils

### Impact visible / technique

Salons peuvent embarquer catalogues site ; forum posts en liste pleine largeur avec tags/thumb ; settings user style Discord ; grades site limités sur popovers. Pas de déploiement.

### Fichiers

forum-voice.ts, forum-official-server.ts, forum-channel-content-embed.ts, site-profile-grades.ts, api/.../channels/route.ts, api/.../channels/[channelId]/route.ts, api/.../tags/route.ts, api/.../tags/[tagId]/route.ts, api/.../forum-posts/route.ts, api/.../forum-posts/[postId]/route.ts, ForumGroupContentEmbedPanel.tsx, ForumGroupForumChannelView.tsx, ForumGroupChannelEditModal.tsx, ForumGroupCommunityPanel.tsx, SiteAppSettingsModal.tsx, UserProfilePopover.tsx, SiteAppProfileModal.tsx, docs/RECAP-…

2026-08-13 09:20 — Deploy web-prod batch UX `/app` 18 points (vagues A–D)

### Contexte

Livraison complète du plan App UX batch 18 après vagues A–D.

### Changements

### Impact

Les 18 points (modals, vanity invite, membres, forum Discord-like, settings user, Éclipse, rail mobile, translate A-Za-z) sont en production.

### Fichiers

Déploiement uniquement (deploy.sh).

  • Build + swap .next-staging + restart web-prod (BUILD_ID: vnOsDKKzbXNgVygiZi5tI).
2026-08-13 09:03 — Vague B App UX batch 18 : vanity invite, membres, stickers, retrait Social

### Contexte

Vague B du plan App UX batch 18 : domaine vanity = URL racine, panneau membres enrichi, fix ajout stickers/expressions, retrait de l’onglet Social (?tab=forum).

### Changements

#### 6. Domaine vanity = racine

#### 7. Panneau membres enrichi

#### 8. Fix ajout sticker / expressions

#### 10. Retrait onglet Social

### Impact visible / technique

Lien vanity = landing join sur la racine du domaine custom ; codes éphémères restent sur lbxmb.fr. Membres settings plus informatifs avec actions. Stickers : erreurs visibles. Onglet Social disparu de la nav app. Pas de déploiement.

### Fichiers

forum-group-permissions.ts, proxy.ts, api/.../invite-domains/[host]/route.ts, invite/host/[host]/page.tsx, MessageLinkEmbeds.tsx, ForumGroupSettingsModal.tsx, ForumGroupRolesPanel.tsx, api/.../members/route.ts, use-forum-social.ts, UserProfilePopover.tsx, ForumGroupCommunityPanel.tsx, ForumGroupExpressionsPanel.tsx, site-app-styles.ts, SiteAppSidebar.tsx, SiteAppShell.tsx, docs/RECAP-…

2026-08-13 08:58 — Vague A App UX batch 18 : modales, dossiers, DnD, échelle UI

### Contexte

Vague A du plan App UX batch 18 : permissions salon (overlay + picker rôles), paramètres serveur fullscreen mobile, ColorPicker + icône dossier rail, bannière 960×540, DnD salons/catégories, échelle UI / taille messages.

### Changements

### Impact visible / technique

Modales serveur/salon couvrent correctement le viewport (rail inclus) ; dossiers rail personnalisables (couleur + image) ; réordonnancement salons par drag ; densité UI / taille messages réglables côté client. Pas de déploiement.

### Fichiers

ForumGroupChannelEditModal.tsx, ForumGroupSettingsModal.tsx, ColorPicker.tsx, SiteAppServerRailList.tsx, forum-server-rail-layout.ts, api/.../me/server-rail/folder-icon/route.ts, site-app-theme.ts, SiteAppSettingsModal.tsx, SiteAppShell.tsx, ChatMessageRow.tsx, SiteAppDmChat.tsx, ForumGroupCommunityPanel.tsx, docs/RECAP-…

  • ForumGroupChannelEditModal : overlay fixed inset-0 z-[100], zone permissions min-w-0 + labels tronqués + scroll fiable + footer sticky ; select natif remplacé par picker rôles searchable (liste + chips).
2026-08-12 22:39 — Fix build client : constantes officielles + layout rail

### Contexte

Le build prod échouait : SiteAppServerRailList (client) importait forum-official-server / forum-server-rail qui tiraient fs via la chaîne serveur.

### Changements

### Impact

/app rebuildable ; rail dossiers + tags en prod.

### Fichiers

forum-official-constants.ts, forum-official-server.ts, forum-server-rail-layout.ts, forum-server-rail.ts, SiteAppServerRailList.tsx, docs/RECAP-…

  • forum-official-constants.ts (slug/nom safe client) ; forum-official-server réexporte.
  • forum-server-rail-layout.ts (parse/merge purs) ; forum-server-rail.ts garde load/save DB.
  • Client rail importe constants + layout uniquement.
  • Déploiement web-prod OK (BUILD_ID: OgTdO0w0MpU8l92NLzT1v).
2026-08-12 22:36 — Vague 3 : tag serveur (5 chars + icône + badge) + rail dossiers

### Contexte

Vague 3 du plan communauté : tags serveur courts avec icône, préférence utilisateur, badge Discord-like ; réordonnancement rail serveurs via layout JSON + dossiers.

### Changements

### Impact visible / technique

Les membres peuvent afficher un tag serveur (≤5) à côté du pseudo ; le rail /app se réordonne et groupe en dossiers. Pas de déploiement.

### Fichiers

forum-group-permissions.ts, forum-voice.ts, forum-server-tag.ts, forum-server-rail.ts, api/.../groups/[slug]/route.ts, api/.../summary/route.ts, api/.../messages/route.ts, api/.../me/primary-tag/route.ts, api/.../me/server-rail/route.ts, api/users/[id]/route.ts, ServerTagBadge.tsx, ForumGroupSettingsModal.tsx, SiteAppSettingsModal.tsx, SiteAppServerRail.tsx, SiteAppServerRailList.tsx, ForumGroupCommunityPanel.tsx, UserProfilePopover.tsx, SiteAppProfileModal.tsx, docs/RECAP-…

  • Schéma : forum_groups.tag → VARCHAR(5) ; tag_icon_url VARCHAR(512) ; users.primary_server_tag_group_id ; table forum_user_server_rail (user_id PK, layout_json JSON).
2026-08-12 22:35 — Vague 2 : domaine invite custom, bannière profil SiteApp, menu contextuel serveur partagé

### Contexte

Vague 2 du plan communauté : domaine d'invitation personnalisé au niveau serveur, bannière profil dans SiteApp, factorisation du menu contextuel serveur (rail + en-tête communauté).

### Changements

#### Domaine d'invitation custom

#### Bannière profil SiteApp

#### Menu contextuel serveur partagé

### Impact visible / technique

Liens d'invitation peuvent utiliser un hostname custom ; embeds invite fonctionnent hors lbxmb.fr ; bannière éditable dans /app ; menu serveur cohérent rail ↔ panneau. npx tsc --noEmit OK. Pas de deploy.

### Fichiers

forum-group-permissions.ts, api/.../groups/[slug]/route.ts, api/.../groups/[slug]/invites/route.ts, api/.../invites/[code]/route.ts, MessageLinkEmbeds.tsx, ForumGroupSettingsModal.tsx, ForumGroupCommunityPanel.tsx, ServerContextMenu.tsx, SiteAppServerRail.tsx, SiteAppSettingsModal.tsx, UserProfilePopover.tsx, SiteAppProfileModal.tsx, docs/RECAP-…

2026-08-12 22:25 — Vague 1 : expressions hideTabs/modal ACL, picker emoji composer, DnD catégories, fix [[E0]]

### Contexte

Vague 1 du plan communauté : UX expressions (onglets masqués depuis settings, modal d'ajout + rôles), picker emoji dans le composer salon, réordonnancement drag-and-drop des catégories, durcissement anti-fuite jetons traduction [[E0]] / [E0].

### Changements

### Impact visible / technique

Paramètres Expression sans double barre d'onglets ; ajout d'emoji/sticker/son avec restriction de rôles ; insertion d'emojis classiques/serveur dans le chat ; catégories réordonnables ; noms emoji ne montrent plus [[E0]].

### Fichiers

ForumGroupExpressionsPanel.tsx, ForumGroupSettingsModal.tsx, api/.../expressions/route.ts, MessageComposerBar.tsx, ForumGroupCommunityPanel.tsx, libretranslate.ts, TranslatedText.tsx, docs/RECAP-…

  • ForumGroupExpressionsPanel : prop hideTabs ; sync type depuis initialType ; formulaire inline remplacé par bouton + modal (nom, fichier, multi-select rôles « canUse ») ; POST FormData + roleIds JSON ; PATCH ACL client si rôles sélectionnés.
2026-08-12 21:53 — Vague C : guide Nextendo stub, Outils/Emulateurs, emoji translate, move salon drag-only

### Contexte

Vague C du plan rôles/invites : contenu site (guide Nextendo, catégories ressources), fix traduction emoji sur noms de salons, déplacement salon uniquement via drag-and-drop.

### Changements

### Impact visible / technique

Noms de salons emoji ne fuient plus LBXMB_EMOJI_0 ; filtres ressources Outils/Emulateurs disponibles ; guide stub visible sous Switch. Traduction FR complète Nextendo dès collage du contenu source.

### Fichiers

web/src/lib/libretranslate.ts, web/src/components/i18n/TranslatedText.tsx, web/src/lib/consoles-config.ts, web/src/components/forum/ForumGroupCommunityPanel.tsx, web/content/guides/nextendo-setup.fr.md, guides (DB id 14), docs/RECAP-…

  • Guide Nextendo : entrée DB guides id=14 (Nintendo Switch / Pack Jailbreak, format github_readme) + fichier web/content/guides/nextendo-setup.fr.md — avertissement non-officiel conservé ; contenu détaillé en attente du markdown source (rentry /raw protégé).
2026-08-12 21:50 — Vague B rôles/invites : nav settings groupée + invitations créées/redeem + embeds

### Contexte

Vague B du plan rôles/invites : navigation paramètres serveur regroupée (style Discord), invitations forum avec expiration / max uses / rôles à l'arrivée, page de redeem publique, embeds de liens d'invitation dans le chat.

### Changements

### Impact visible / technique

Création d'invitations complètes, join des serveurs privés via code, embeds cliquables dans les messages. /invite/[code] (chat) inchangé. bunx tsc --noEmit OK.

### Fichiers

forum-group-permissions.ts, api/.../groups/[slug]/invites/route.ts, api/.../invites/[code]/route.ts, api/.../groups/[slug]/summary/route.ts, app/invite/g/[code]/page.tsx, app/invite/g/[code]/layout.tsx, ForumGroupInviteCreateModal.tsx, ForumGroupSettingsModal.tsx, ForumGroupExpressionsPanel.tsx, SiteAppServerRail.tsx, MessageLinkEmbeds.tsx, docs/RECAP-…

  • Schéma forum_group_invites : colonnes expires_at DATETIME NULL, grant_role_ids JSON NULL (via ensureColumn + CREATE) ; helpers forumGroupInvitePublicUrl, parseInviteGrantRoleIds, inviteIsExpired, inviteIsExhausted.
2026-08-12 21:47 — Vague A : hiérarchie documentée + tests exécutables

### Contexte

Compléments à la Vague A (fusion multi-agents) : les tests de hiérarchie n'étaient pas lançables (bun absent ; Node ne résout pas un import TS relatif sans extension), et l'ordre de priorité des rôles n'était pas documenté côté résolution.

### Changements

### Impact visible / technique

npm run test:permissions → 6/6 OK ; npx tsc --noEmit OK sur le projet web ; aucun lint sur les fichiers touchés. La hiérarchie est vérifiable en CI sans dépendance supplémentaire.

### Fichiers

web/src/lib/forum-group-permissions-hierarchy.ts, web/src/lib/forum-group-permissions.resolve.test.ts, web/scripts/test-forum-group-permissions.mjs, web/package.json, web/src/components/forum/ForumGroupChannelEditModal.tsx, docs/RECAP-…

  • forum-group-permissions-hierarchy.ts : en-tête documentant l'ordre de priorité — la liste de ForumGroupRolesPanel trie position ASC avec @everyone verrouillé en bas, donc plus petite position = priorité la plus forte et @everyone toujours dernier ; règles 1→5 (owner/ADMINISTRATOR, overwrite membre, overwrites rôles haut→bas premier non neutre, overwrite @everyone, bits de serveur avec @everyone en repli).
2026-08-12 21:43 — Vague A rôles/invites : icône image, hiérarchie, switches, menu contextuel

### Contexte

Vague A du plan rôles/invites : icône image de rôle, retrait du mode couleur balance, interrupteurs bi/tri-état, hiérarchie de permissions (plus d’OR naïf), menu contextuel liste des rôles.

### Changements

### Impact visible / technique

Icônes de rôle persistées ; résolution d’accès alignée sur la priorité visuelle de la liste ; UX permissions cohérente Discord-like. bun test 4/4 OK ; tsc --noEmit OK.

### Fichiers

forum-group-permissions.ts, forum-group-permissions-hierarchy.ts, forum-group-permissions.resolve.test.ts, forum-voice.ts (saveForumGroupRoleIcon), api/.../roles/route.ts, api/.../roles/[roleId]/route.ts, ForumGroupRolesPanel.tsx, PermissionToggle.tsx, ForumGroupChannelEditModal.tsx, globals.css, docs/RECAP-…

  • Schéma forum_group_roles.icon_url via ensureColumn ; upload saveForumGroupRoleIcon (PNG/WebP, scan+sanitize) ; API GET/POST/PATCH rôles exposent iconUrl + multipart iconImage / removeIcon.
2026-08-12 20:41 — Wave 4 expressions/events (compléments)

### Contexte

Alignement API expressions + planning après fusion multi-agents (pas de double UI).

### Changements

### Impact

CRUD expressions/ACL et planning édition/RSVP opérationnels en prod (déjà inclus au dernier deploy).

### Fichiers

forum-group-expressions.ts, expressions/route.ts, expressions/[assetType]/[assetId]/route.ts, events/route.ts, ForumGroupEventsModal.tsx, forum-group-permissions-bits.ts

  • Expressions : bit MANAGE_EXPRESSIONS, ACL @everyone, upload scanné, route asset dédiée.
  • Events : PATCH édition, retrait RSVP au reclic, vérif appartenance serveur.
2026-08-12 20:35 — Vague 2 finalisée : panneau Rôles extrait + schéma couleurs

### Contexte

Deux implémentations concurrentes de l'UI rôles (inline dans ForumGroupSettingsModal + composant ForumGroupRolesPanel) : consolidation en une seule, et complétion des manques (multi-ajout membres, verrou @everyone, reorder en lot côté API).

### Changements

### Impact visible / technique

Réglages rôles lisibles et réordonnables à la souris, couleurs avancées persistées. Une seule source de vérité UI rôles (modal allégé de ~500 lignes). tsc --noEmit OK sur le projet web.

### Fichiers

ForumGroupRolesPanel.tsx, ForumGroupSettingsModal.tsx, lib/forum-group-permissions.ts, api/forum-social/groups/[slug]/roles/route.ts, api/forum-social/groups/[slug]/roles/[roleId]/route.ts, app/globals.css, docs/RECAP-…

  • ForumGroupRolesPanel.tsx : unique implémentation des réglages rôles (sidebar liste + détail, scrolls indépendants, cartes). Onglets Affichage / Permissions / Membres.
  • Affichage : nom, icône (champ texte court, emoji collé — aucun composer emoji), couleur + mode, « afficher séparément », mentionnable, aperçu live.
2026-08-12 20:32 — Batch UX serveur /app (18 points, 4 vagues)

### Contexte

Lot UX : menus salons, profil popover, download, bridge avatar/doublons, rôles modernes, traduction UGC, recherche, vocaux social→officiel, resize vocal, Nativefier, expressions, planning.

### Changements

#### Vague 1

#### Vague 2

#### Vague 3

#### Vague 4

### Impact

UX Discord-like renforcée sur /app ; bridge plus stable ; expressions & events disponibles.

### Fichiers

Nombreux sous web/src/components/forum|site-app|i18n, APIs forum-social/*, bot-forum-bridge/src/communityBridge.js, docs/NATIVEFIER-VOICE.md, docs/RECAP-…

  • Clic droit salon : Modifier → Déplacer → Supprimer (ConfirmDialog).
  • Modal édition salon : onglets à gauche ; delete via ConfirmDialog ; emoji dans le nom.
  • Download rail → modal « app non disponible ».
2026-08-12 19:47 — Drag-and-drop salons + anti-doublon Discord→site

### Contexte

Mode « Déplacer » voulu à la Discord (glisser-déposer à la souris). Images Discord→site arrivant en double (race gateway messageCreate + poll REST pendant le téléchargement PJ).

### Changements

#### Drag-and-drop salons /app

#### Anti-doublon bridge

### Impact

Réorganisation salons à la souris. Un message Discord (surtout avec image) ne doit plus créer deux messages site//app.

### Fichiers

ForumGroupCommunityPanel.tsx, api/internal/community-bridge/route.ts, bot-forum-bridge/src/communityBridge.js, docs/RECAP-…

  • Salons texte/vocal draggable (staff) : glisser entre catégories / positions avec barre bleue d’indication.
  • Drop en fin de catégorie ; API move réutilisée.
  • Click fantôme après drop ignoré ; menu « Déplacer… » conservé en secours.
  • Claim atomique INSERT IGNORE sur community_bridge_messages.discord_message_id avant download PJ (discord_text / discord_forum_reply).
2026-08-12 19:30 — Fix catégories salons + clic droit Déplacer

### Contexte

Assigner des salons à une catégorie faisait « disparaître » les autres (écrasement périodique par le bridge). Pas de UI pour choisir catégorie + position précise.

### Changements

### Impact

Les salons restent dans la catégorie choisie. Déplacement précis via menu contextuel.

### Fichiers

community-bridge.ts, forum-group-channel-move.ts, channels/route.ts, channels/[channelId]/route.ts, ForumGroupCommunityPanel.tsx, ForumGroupSettingsModal.tsx, docs/RECAP-…

  • ensureCommunityBridgeChannels : ne réécrit plus category_id / sort_order des salons déjà liés (placement manuel conservé).
  • API PATCH …/channels type move : catégorie + position (beforeChannelId / fin).
  • Clic droit salon → Déplacer… (catégorie + position avant un salon / haut / bas).
  • Création salon : sort_order = max+1 dans la catégorie cible.
  • Réglages : flèches haut/bas limitées à la même catégorie ; changement de catégorie via move.
2026-08-12 19:18 — Fix bridge webhook identité + PJ + commentaires

### Contexte

Posts site→Discord sans pseudo/avatar, sans images ; commentaires Discord non synchronisés (« thread non mappé »).

### Changements

### Impact

Nouveaux posts/réponses : webhook avec vrai pseudo + photo + PJ. Commentaires Discord↔site↔/app actifs sur fils déjà mappés. Anciens messages Discord déjà postés sans identité ne sont pas réécrits.

### Fichiers

internal/community-bridge/route.ts, community-bridge-helpers.ts, bot-forum-bridge/src/communityBridge.js, bot-forum-bridge/package.json, docs/RECAP-…

  • JOIN auteurs forum site corrigé : users.user_id = forum_threads/posts.author_id (plus users.id).
  • Extraction <!-- ATTACHMENTS:[…] --> + envoi fichiers (lecture disque uploads/ prioritaire).
  • Avatar .webp converti en PNG public (uploads/bridge-avatars/) via sharp avant avatar_url Discord.
  • Sync commentaires : auto-heal mapping community_bridge_threads depuis forum_threads / app posts ; miroirs /app rattrapés (threads 98/100/101).
2026-08-12 19:00 — Sync Discord ↔ forum site ↔ `/app` (3 voies)

### Contexte

Besoin de lier les salons Discord LBXMB (entraide, jeux-vidéo, cinéma, culture, technologie, dév-test, hors-sujet) au serveur officiel /app et au forum classique, avec sync bidirectionnelle live (webhooks, pseudo/avatar).

### Changements

#### Map + salons + superusers

#### UX forum Discord-like /app

#### Bridge webhook multi-canal

#### Fantômes + emojis

### Impact

### Fichiers

community-bridge-map.ts, community-bridge.ts, community-bridge-helpers.ts, community_bridge_map.json, bidirectional_sync_config.json, forum-group-permissions.ts, ForumGroupForumChannelView.tsx, ForumGroupCommunityPanel.tsx, forum-posts/route.ts, forum-posts/[postId]/route.ts, internal/community-bridge/route.ts, messages/route.ts, thread/create/route.ts, forum-thread-reply-core.ts, bot-forum-bridge/src/communityBridge.js, bot-forum-bridge/src/index.js, scripts/sync-official-lbxmb-group.ts, docs/RECAP-…

2026-08-12 18:16 — Serveur social officiel LB'XMB.FR (miroir Discord)

### Contexte

Le côté social /app n’avait pas de serveur par défaut. Objectif : serveur officiel peuplé depuis la guild Discord LBXMB.

### Changements

### Sync initiale

group_id=9 — 22 rôles, 7 catégories, 31 salons texte (23 text / 7 forum / 1 announcement), 3 vocaux, 32 overwrites.

### Impact

Tout user authentifié avec accès groupes rejoint auto LB'XMB.FR ; structure alignée Discord (sans messages/membres Discord).

### Fichiers

forum-official-server.ts, discord-guild-structure-sync.ts, groups/route.ts, groups/[slug]/leave, groups/[slug]/route.ts DELETE, channels/route.ts, official/sync-discord/route.ts, SiteAppServerRail.tsx, ForumGroupCommunityPanel.tsx, use-forum-social.ts, scripts/sync-official-lbxmb-group.ts, docs/RECAP-…

  • Seed forum_groups slug lbxmb-fr, name LB'XMB.FR, is_official=1, avatar groups/official-lbxmb.png (copie de /lbxmb.png).
2026-08-12 09:24 — Self-host full-stack phase 2 (agent serveur)

### Contexte

Phase 1 = LiveKit remote only. Besoin de gérer salons, rôles, permissions, profil serveur, bans, messages sur le VPS utilisateur.

### Décision

Hybrid : /app + auth lbxmb.fr ; données serveur + uploads sur agent VPS ; vocal LiveKit remote inchangé.

### Changements

### Impact

Un serveur auto-hébergé avec URL agent stocke salons/rôles/bans/messages sur le VPS ; le client /app ne change pas d’UX. Nouveaux serveurs only (pas de migration auto).

### Fichiers

infra/self-host-agent/*, forum-group-selfhost.ts, forum-group-agent-proxy.ts, routes forum-social/groups/**, internal/selfhost/*, ForumGroupsShell.tsx, ForumGroupSettingsModal.tsx, ForumGroupCommunityPanel.tsx, docs/RECAP-…

  • Pack infra/self-host-agent/ : Node agent + Postgres + LiveKit/Coturn, API /v1/* (profil, channels, roles, bans, members, invites, messages, uploads), JWT session, heartbeat, fan-out realtime + ban-sync vers plateforme.
2026-08-12 08:57 — Bugs bot/web + self-host vocal phase 1

### Contexte

Avatar webhook d’annonces manquant ; boutons réaction « Annonce introuvable » ; traductions FR→FR inutiles ; démarrage self-host LiveKit remote pour serveurs /app.

### A1 — Avatar webhook annonces

### A2 — Boutons réaction annonce

### A3 — Skip même langue (FR→FR)

### B — Self-host vocal phase 1 (média LiveKit remote)

### Impact

Réactionsitions annonces Discord (avatar + réactions) ; plus de reformulation FR→FR ; un serveur /app peut pointer son LiveKit VPS (texte reste central).

### Fichiers

forumWebTranslateHandler.js, libretranslate.ts/js, discordLocale.js, translateForInteraction.js, autoTranslationHandler.js, customCommandTranslate.js, thread/create/route.ts, forumAnnouncementPost.js, discordRest.js, forum-group-selfhost.ts, groups/route.ts, groups/[slug]/route.ts, voice/token/route.ts, ForumGroupsShell.tsx, ForumGroupSettingsModal.tsx, ForumGroupCommunityPanel.tsx, selfhost-heartbeat/route.ts, infra/self-host-voice/*, docs/RECAP-…

2026-08-12 08:28 — INP mobile homepage + hydratation #418

### Contexte

PageSpeed : CWV mobile Failed (INP ~313 ms). Lab perf ~67–75. Hydration React #418 probable (perf-mode / dates / Hero).

### Changements

### Impact

Moins de travail main-thread au first paint mobile → INP ; moins de mismatch hydratation.

### Fichiers

AppScrollShell.tsx, DeferredLightRays.tsx, PageLightRaysBackdrop.tsx, Hero.tsx, TextType.tsx, ShinyText.tsx, Footer.tsx, HomeFeedCarousel.tsx, Testimonials.tsx, HomeBelowFold.tsx, Header.tsx, usePreferLiteUi.ts, stable-date.ts, docs/RECAP-…

  • AppScrollShell : scroll natif sur mobile/coarse ; scrollbar custom desktop uniquement.
  • DeferredLightRays : next/dynamic + idle ; PageLightRaysBackdrop : WebGL desktop only (CSS gradient mobile/perf).
  • Hero : chemin lite (mobile/perf) sans TextType/gsap, ShinyText, CountUp, motion ; prefetch={false} CTAs.
  • TextType / ShinyText : même arbre au first paint ; animations après mount desktop.
2026-08-11 21:07 — Vocal self-hosted sur Canaux (151.240.100.62)

### Contexte

LiveKit Cloud en 429. Refus d’exposer la box 86.241.102.88. 2ᵉ NIC VM Canaux = 151.240.100.62 pour le média WebRTC.

### Changements

### Impact

Signal via nginx wss://lbxmb.fr/livekit. Média/ICE/TURN sur IP publique VM Canaux (pas de NAT box). E2EE vocal conservé. STUN/TCP 3478/7881 OK sur .62.

### Fichiers

livekit/livekit.yaml, livekit/turnserver.conf, web/.env.local, bot-forum-bridge/.env, web/server.js, ecosystem.config.js, /usr/local/sbin/canaux-policy-routing.sh, /etc/systemd/system/canaux-policy-routing.service, docs/RECAP-TRAVAIL-COMMUNAUTE-2026-04.md

  • Policy routing persisté : traffic sourcé .62 → gateway 151.240.100.1 via Canaux (canaux-policy-routing.service + /usr/local/sbin/canaux-policy-routing.sh).
  • livekit/livekit.yaml : use_external_ip: false, node_ip: 151.240.100.62, TURN WAN .62 + LAN 192.168.1.112.
  • livekit/turnserver.conf : relay-ip / external-ip = 151.240.100.62.
2026-08-11 20:55 — Vocal : retour LiveKit Cloud + E2EE (sans ports box)

### Contexte

Pas d’exposition NAT/box pour le média WebRTC. Self-hosted OK en LAN seulement. Bascule prod vers LiveKit Cloud + réactivation E2EE vocal.

### Changements

### Impact

Média via SFU Cloud (pas de ports maison). E2EE vocal opt-in actif. Attention : le projet Cloud actuel renvoie encore 429 minutes limit exceeded — il faut un nouveau projet / upgrade sur cloud.livekit.io et mettre à jour les clés.

### Fichiers

.env.local, bot-forum-bridge/.env, ForumVoiceSession.tsx

  • web/.env.local + bot-forum-bridge/.env : LIVEKIT_USE_CLOUD=1, URLs/clés projet lb-xmb-fr-tvls6smf, NEXT_PUBLIC_E2EE_VOICE=1.
  • Message d’erreur si quota Cloud (429 connection minutes).
  • Deploy web-prod + restart bridge.
2026-08-11 20:45 — Vocal hors LAN : LiveKit use_external_ip + TURN relay WAN

### Contexte

Vocal OK en réseau local, KO depuis Internet. Cause : livekit.yaml avait use_external_ip: false + node_ip: 192.168.1.112 → candidats ICE LAN injoignables hors box.

### Changements

### Impact

Les clients Internet reçoivent des candidats publics / TURN au lieu de 192.168.1.112.

### Prérequis box

Forward vers 192.168.1.112 : UDP/TCP 3478, UDP 49160–49200, TCP 7881, UDP 50000–50200.

### Fichiers

livekit/livekit.yaml, forum-voice.ts, ForumVoiceSession.tsx

  • livekit/livekit.yaml : use_external_ip: true, node_ip: 86.241.102.88, TURN public + LAN.
  • forum-voice.ts : filtre les STUN IP privées pour clients hors LAN.
  • ForumVoiceSession.tsx : clients hors LAN démarrent en iceTransportPolicy: relay (TURN).
  • Restart lbxmb-livekit + lbxmb-coturn.
2026-08-11 20:28 — Vocal spinner : setRoom jamais bloqué par E2EE + flag vocal opt-in

### Contexte

Toujours spinner pour les autres alors qu’ils étaient dans LiveKit. Cause structurelle : chemin late-joiner E2EE faisait connect puis waitOnly/enableRoomE2ee avant setRoom. Flag NEXT_PUBLIC_E2EE_VOICE=0 fragile (défaut ON si process ambigu).

### Changements

### Impact

Présence LiveKit = scène affichée ; plus de spinner infini post-connect.

### Fichiers

e2ee-flags.ts, ForumVoiceSession.tsx

  • e2ee-flags.ts : E2EE vocal opt-in uniquement ("1" / "true"), défaut OFF.
  • ForumVoiceSession.tsx : connect puis setRoom sans attendre une clé late-joiner ; E2EE late en arrière-plan si jamais réactivé.
2026-08-11 20:22 — Vocal : fin du spinner (setRoom avant micro) + E2EE voice off

### Contexte

Après le fix late-joiner E2EE, d’autres users restaient en chargement alors qu’ils apparaissaient déjà dans LiveKit (forum_voice_1). Aucun seal voice_channel en base ; le blocage était après connect, sur getUserMedia / RNNoise (attente permission micro) avant setRoom.

### Changements

### Impact

Les late joiners voient la scène même si le micro est en attente ; plus de spinner infini lié au GUM. Vocal sans E2EE pour rétablir le multi-user.

### Fichiers

ForumVoiceSession.tsx, web/.env.local, livekit-e2ee.ts

  • ForumVoiceSession.tsx : setRoom + fin du connecting dès le signal LiveKit ; micro en arrière-plan avec timeout 12s.
  • NEXT_PUBLIC_E2EE_VOICE=0 : chiffrement vocal désactivé tant que la distrib de clés multi-users n’est pas fiable (DM/canaux texte inchangés).
  • ensureIdentityPublished : échoue si le POST device-keys échoue.
2026-08-11 20:13 — Vocal multi-users : redistrib E2EE late joiners

### Contexte

Un user se connectait au vocal, les autres restaient en chargement. Cause : clé E2EE scellée uniquement pour le 1er ; les suivants avaient hasAny sans ciphertext. De plus, le poll avant connect empêchait le 1er de re-sceller (chicken-egg).

### Changements

### Impact

Les utilisateurs qui rejoignent après le 1er peuvent obtenir la clé E2EE et quitter le spinner.

### Fichiers

resolve-media-room-key.ts, ForumVoiceSession.tsx, api/forum/voice/token/route.ts, forum-voice.ts

  • resolve-media-room-key.ts : export publishSeals / resealMediaRoomKeyForUsers / peekMediaRoomSeal ; poll ~22s pour late joiners ; mode waitOnly.
  • ForumVoiceSession.tsx : late joiner connecte d’abord puis attend la clé ; re-scellage immédiat sur ParticipantConnected ; timeout connect 25s.
  • token/route.ts : e2eeRecipientUserIds inclut les participants LiveKit déjà présents.
  • forum-voice.ts : purge e2ee_sealed_room_keys quand la room est vide.
2026-08-11 20:00 — Vocal /app : bascule LiveKit self-hosted (quota Cloud)

### Contexte

Après le fix CSP, nouvelle erreur : Encountered websocket error during connection establishment. Diagnostic : LiveKit Cloud répond 429 connection minutes limit exceeded. Self-hosted (wss://lbxmb.fr/livekit, container lbxmb-livekit) OK.

### Changements

### Impact

Le token vocal pointe vers wss://lbxmb.fr/livekit (plus de quota Cloud). ICE Coturn maison réactivé hors Cloud.

### Fichiers

web/.env.local, bot-forum-bridge/.env, web/server.js, ForumVoiceSession.tsx, ForumVoiceCallStage.tsx

  • web/.env.local + bot-forum-bridge/.env : URLs/clés self-hosted, LIVEKIT_USE_CLOUD=0.
  • web/server.js : force-reload des vars LiveKit/TURN depuis .env.local (PM2 gardait l’ancien Cloud).
  • Messages d’erreur vocal (quota / websocket) dans ForumVoiceSession + ForumVoiceCallStage.
  • Restart web-prod + bot-forum-bridge.
2026-08-11 19:51 — Vocal /app : CSP LiveKit Cloud (signal NetworkError)

### Contexte

Sur /app, connexion vocal échouait avec could not establish signal connection: NetworkError when attempting to fetch resource. Le message UI pointait à tort vers les permissions micro Waterfox. Cause : connect-src CSP sans https://*.livekit.cloud — le SDK LiveKit fetch régions/validate en HTTPS.

### Changements

### Impact

Les fetch HTTPS LiveKit Cloud ne sont plus bloqués par la CSP ; message utilisateur moins trompeur.

### Fichiers

web/src/lib/csp.ts, web/src/components/forum/ForumVoiceCallStage.tsx

  • csp.ts : ajout https://*.livekit.cloud, wss://*.livekit.cloud, https://*.livekit.run, wss://*.livekit.run dans CONNECT_SOURCES.
  • ForumVoiceCallStage.tsx : message d’erreur différencié (signal/réseau vs micro vs générique) + détail technique affiché.
2026-08-09 00:27 — Cards boutique/profil : chrome unifié + icônes intactes

### Contexte

Cards catégorie vs produit de tailles/styles incohérents ; icônes produit rognées (object-cover) sur le profil.

### Changements

### Impact

Catalogue + profil plus cohérents ; logos/icônes lisibles dans les cards.

### Fichiers

shop-category.ts, CategoryCard.tsx, ProductCard.tsx, profile/Shop.tsx

  • Tokens partagés SHOP_CATALOG_CARD_* (shell, média 4/3, body, titre, meta, prix).
  • CategoryCard + ProductCard alignés sur le même chrome.
  • Produits : icônes en object-contain + padding (plus de crop agressif).
  • Grille profil : mêmes gaps que le catalogue boutique.
2026-08-09 00:21 — Profil mobile : même fond glass que Naviguer

### Contexte

Le sheet profil mobile n’avait pas le même flou glass que le menu Naviguer.

### Changements

### Impact

Cohérence visuelle entre Naviguer et options profil sur mobile.

### Fichiers

ProfileMenuSheet.tsx

  • ProfileMenuSheet : glass-darker + bordures alignées sur MobileNavigateSheet (au lieu de bg-[#0c0c0e]/95 backdrop-blur-xl).
2026-08-08 23:46 — /discord = redirect invite (sans landing)

### Contexte

L'utilisateur veut uniquement la redirect lbxmb.fr/discord → https://discord.gg/kVC27qXsbE, sans page dédiée.

### Changements

### Impact

Plus de landing ; ouverture directe de l'invite Discord.

### Fichiers

next.config.js, discord/page.tsx

  • Redirect Next restaurée dans next.config.js.
  • discord/page.tsx : redirect(DISCORD_INVITE_URL) (filet de sécurité).
2026-08-08 23:33 — Commande Discord `/invite` (bouton Link → modal join)

### Contexte

Clarification : modal de join Discord via bouton dans un message Discord (pas via le site).

### Changements

### Impact

/invite dans un salon → bouton cliquable qui ouvre le modal Discord « Rejoindre ».

### Fichiers

bot-public/src/commands/util/invite.js, serverConfig.js, guard.js, help.js

  • Nouvelle commande publique /invite : container V2 + bouton Link « Rejoindre le serveur » → https://discord.gg/kVC27qXsbE (ouvre le modal invite Discord).
  • Ajoutée à DEFAULT_COMMANDS + PUBLIC_COMMANDS + help.
2026-08-08 23:30 — Page /discord restaurée (bouton invite)

### Contexte

Tester le join Discord via bouton (ouvre l’invite → modal Discord) plutôt qu’une redirect directe.

### Changements

### Impact

lbxmb.fr/discord affiche la landing ; le bouton ouvre l’invite Discord (modal join côté Discord).

### Fichiers

discord/page.tsx, next.config.js

  • Suppression redirect /discord → discord.gg dans next.config.js.
  • Restauration de la page /discord (stats + CTA « Rejoindre le Discord » → DISCORD_INVITE_URL en nouvel onglet).
2026-08-08 23:24 — Nav : Discord retiré + Naviguer mobile

### Contexte

Retirer Discord de la navbar ; /discord → invite directe ; remanier la bottom nav mobile.

### Changements

### Impact

Lien Discord = invite directe ; navigation mobile via sheet bas.

### Fichiers

Header.tsx, MobileBottomNav.tsx, MobileNavigateSheet.tsx, discord/page.tsx, next.config.js, discord.ts, messages/*.json, .env.local

  • Navbar desktop : entrée Discord retirée.
  • /discord redirige vers https://discord.gg/kVC27qXsbE (next.config + page + invite URL).
  • Bottom nav mobile : Accueil → Naviguer (sheet bottom comme notifications) avec Accueil, Guides, Ressources, Forum, Boutique, Outils, Faire un don.
  • Icône menu ⋮ (trois points) retirée du header mobile.
2026-08-08 22:49 — Boutique hors-rayon + Discord shop + /sanction modal

### Contexte

1. KV / CID (sans catégorie) invisibles sur le hub /boutique.

2. Salon Discord boutique : fils obsolètes (produits disparus) + nouveaux produits non postés (auto-approve sans hook Discord).

3. /sanction : remettre une modale ; titre container avec ping rôle + allowedMentions.

### Changements

#### Hub boutique

#### Sync Discord boutique

#### /sanction

### Impact

### Fichiers

boutique/page.tsx, api/shop/request/route.ts, sanction.js, communitySanctionHandler.js, discord-site-forum-sync.json

  • Produits category vide/NULL affichés en ProductCard à côté des CategoryCard.
  • POST /api/shop/request : capture insertId + postSiteContentToDiscordForum si auto-approuvé.
  • Nettoyage : 16 fils Discord orphelins supprimés ; backfill 37 produits manquants (KV/CID déjà OK). Total sync shop: = 39.
2026-08-08 17:59 — Boutique : édition options + modale suppression dashboard

### Contexte

1. Impossible de modifier correctement les compléments/options d’un produit (édition).

2. Sur le dashboard boutique, la modale de confirmation de suppression était cassée (overlay coincé / mal positionné).

### Changements

#### Options produit (édition)

#### Modale suppression dashboard

### Impact

### Fichiers

BoutiqueProductForm.tsx, ShopRequestsPanel.tsx

  • Clés React des variantes basées sur un id stable (plus sur label/price_delta) → plus de perte de focus à chaque frappe.
  • Hydratation du formulaire edit une seule fois par produit (ref) pour éviter qu’un refetch React Query écrase les saisies.
  • Remplacement de l’overlay maison (fixed dans une card overflow-hidden + blur) par ConfirmDialog (portal Radix, z-[300]).
2026-08-08 17:36 — Mode perf : coupe anim @ profil + LogoLoop

### Contexte

Le mode performance ne coupait pas le loader @ animé (Framer pathLength) ni le délai 800ms / fade blur sur /profil et /profil/[pseudo]. LogoLoop ignorait aussi perf-mode.

### Changements

### Impact

Appareils faibles : plus d’anim Framer / typewriter / carrousel RAF liés à ces surfaces.

### Fichiers

profil/page.tsx, ui/at-sign.tsx, LogoLoop.tsx

  • Profil : en mode perf, pas d’AtSign animé, pas d’overlay 800ms, contenu immédiat (Loader2 statique pendant fetch).
  • AtSignIcon : SVG statique + startAnimation no-op si perf.
  • LogoLoop : respecte html.perf-mode (plus de RAF).
2026-08-08 17:12 — Mode performance : zéro animation

### Contexte

Le mode perf coupait surtout le CSS ; Framer / TextType / ShinyText / CountUp continuaient.

### Changements

### Fichiers

ReducedMotionObserver.tsx, useReducedMotion.ts, usePerformanceMode.ts, TextType.tsx, ShinyText.tsx, Hero.tsx, globals.css, fr.json, en.json

  • MotionConfig reducedMotion="always" si perf.
  • useReducedMotion = prefers-reduced-motion ou mode perf.
  • TextType : texte complet (pas de typewriter/GSAP).
  • ShinyText : texte statique.
  • Hero : CountUp instantané + motions sans entrée.
  • CSS perf : animate-*, fade/slide-in, transforms hover, view-transitions coupés.
  • Libellés FR/EN mis à jour.
2026-08-08 17:05 — Sondages : en-tête `# 📊 Titre | @mention` (edit in-place)

### Contexte

En-tête sans # ; besoin d’éditer les messages existants sans renvoyer (pas de MP).

### Changements

### Fichiers

forumPollBridge.js, internalHttpServer.js

  • En-tête : # 📊 Titre | <@&rôle>.
  • allowRolePing uniquement à la 1ʳᵉ publication (edit/sync sans re-ping Discord).
  • editForumPollLayoutInPlace + endpoint /internal/forum/poll-edit-layout (edit only).
  • Messages ouverts édités in-place (pas de renvoi → pas de MessageCreate → pas de MP).
2026-08-08 17:02 — MP notif : uniquement bot / webhook

### Contexte

Un message membre dans annonces / sondages / etc. déclenchait aussi les MP.

### Changements

### Fichiers

notifChannelDm.js, messageCreate.js

  • DM seulement si webhookId ou auteur = le bot.
  • Les messages utilisateurs dans ces salons n’envoient plus de MP.
2026-08-08 17:00 — MP notif sondages réactivés

### Changements

### Fichiers

notifChannelDm.js

  • Retrait de sondages de NOTIF_DM_DISABLED_KEYS.
  • Les publications salon sondages renvoient à nouveau les MP (opt-out bouton).
2026-08-08 16:58 — Sondages Discord : container seul + mention dedans

### Contexte

Retour à un seul container ; mention dans le container (📊 Titre | <@&rôle>). Pas de republish des messages existants.

### Changements

### Fichiers

forumPollBridge.js, notifChannelDm.js

  • Payload = 1 Container (plus de TextDisplay hors container).
  • En-tête : 📊 Titre | <@&role> + allowedMentions.roles.
  • MP sondages toujours coupés ; note TODO : opt-in notifs par défaut (annonces/actu/sondages) + opt-out bouton.
2026-08-08 16:55 — Sondages Discord : webhook = pseudo + photo site

### Contexte

Les messages migrés s’affichaient comme « Forum » sans avatar site.

### Changements

### Fichiers

forumPollBridge.js, internalHttpServer.js, thread/create/route.ts

  • Webhook envoie username + avatarURL (résolution HTTPS depuis photo site).
  • Stockage authorPseudo / authorAvatar sur le poll.
  • Republish récupère l’auteur via /api/forum-social/thread/{id} si besoin, puis renvoie le message (Discord n’applique l’identité qu’à l’envoi).
  • Create route : absoluteUploadUrl / getPhotoUrl pour l’avatar.
2026-08-08 16:52 — Sondages Discord : 1 message V2 (header + container)

### Contexte

Deux messages (ping + container) n’étaient pas le rendu voulu.

### Changements

### Fichiers

forumPollBridge.js

  • Un seul message Components V2 :
  • TextDisplay hors container : # <@&role> | Titre
  • Container : description + meta + options/votes + boutons
  • Publier / sync / votes / republish alignés sur ce layout
  • Suppression de l’ancien message ping séparé au republish
2026-08-08 16:50 — MP notif sondages désactivés

### Contexte

Les publications dans le salon sondages (webhook inclus) déclenchaient des MP massifs alors que le format n’est pas finalisé.

### Changements

### Fichiers

bot-public/src/lib/notifChannelDm.js

  • NOTIF_DM_DISABLED_KEYS : clé sondages → aucun DM tant que le layout poll n’est pas stable.
  • Annonces / actualités inchangées.
2026-08-08 16:24 — Boutique : hub catégories, grille 5, cartes compactes

### Contexte

La boutique listait tous les produits (souvent 3 cols desktop). Besoin d’un catalogue par catégories + densification.

### Changements

### Fichiers

shop-category.ts, CategoryCard.tsx, ProductCard.tsx, boutique/page.tsx, boutique/c/[slug]/page.tsx, api/shop/categories/route.ts, boutique/[id]/page.tsx, BoutiqueProductForm.tsx

  • /boutique = hub de catégories (cartes image + compteur + prix min).
  • /boutique/c/[slug] = produits de la catégorie (recherche, breadcrumb).
  • Grille 2 / 3 / 5 cols (min-[700px] / min-[1000px]), indépendante du breakpoint 1340px.
  • ProductCard size=shop densifié (~1,5×).
  • API GET /api/shop/categories (agrégation SQL, pas de nouvelle table).
  • Compat /boutique?category= → redirect slug ; breadcrumb fiche produit mis à jour.
  • Aide formulaire vendeur : « la boutique affiche d’abord les catégories ».
2026-08-08 16:14 — Votes sanction : décision uniquement à la fin (24 h)

### Contexte

Un ban s’appliquait dès 75 % atteint (ex. 3 pour / 1 contre), sans attendre la fin du vote.

### Changements

### Fichiers

communitySanctionHandler.js, communitySanctionStore.js

  • Plus de clôture anticipée après un vote.
  • À l’expiration 24 h : decideFromVotes (75 %, min 4 votes) → apply / reject / expired si pas de majorité.
  • Textes UI mis à jour (« décision à la fin des 24 h »).
2026-08-08 16:08 — Votes sanction : bypass ancienneté

### Contexte

Certains membres doivent pouvoir voter aux sanctions communautaires sans attendre 2 semaines sur le serveur.

### Changements

### Fichiers

communitySanctionStore.js, communitySanctionHandler.js

  • Whitelist COMMUNITY_VOTE_MEMBERSHIP_BYPASS_IDS : 774721833241018430, 1011936763742277662, 1250019013250121770.
  • assertVoterEligibility saute le contrôle d’ancienneté pour ces IDs.
2026-08-08 16:00 — Sondages Discord : webhook + participants éphémères

### Contexte / problème

### Changements appliqués

### Impact

### Fichiers

forumPollBridge.js, sondage.js, pollScheduler.js, thread/create/route.ts

  • Sondages forum postés en Components V2 (bot) au lieu d’un webhook comme annonces/actus.
  • Liste des participants inline illisible dès qu’il y a beaucoup de votes.
  • Publication sondage via webhook « Forum Web » : message classique # <@&role> | Titre + corps + barres + boutons.
  • Plus de noms de votants dans le message ; bouton Voir les participants → détail éphémère (réponses).
  • Même règle pour /sondage natif (plus de liste inline, bouton participants).
  • Avatar/pseudo auteur passés au webhook.
  • Affichage Discord aligné sur les annonces ; participants à la demande.
2026-08-08 15:54 — Fix redirect vérif hors serveur principal

### Contexte / problème

Après OAuth sur /verify/{guildId} (ex. 152849…), redirection encore vers /commencer?step=prefs (next OAuth ou confusion DISCORD_GUILD_ID).

### Changements appliqués

### Impact

Vérif d’un serveur tiers reste sur sa page /verify/{id} (succès/échec).

### Fichiers

verify-oauth-callback-logic.ts, authorize/route.ts, VerifyClient.tsx

  • Callback : hors guild principale → toujours /verify/{id}?verified=1 (ignore next vers /commencer).
  • isMainGuild : uniquement COMMENCER_GUILD_ID / ID LB'XMB fixe (plus de fallback DISCORD_GUILD_ID).
  • Authorize + VerifyClient : ne passent plus de next=/commencer pour les autres guilds.
2026-08-08 15:42 — Sondages forum ↔ Discord (sync votes + durée)

### Contexte / problème

### Changements appliqués

### Impact

### Fichiers touchés

  • Sondages forum : pas de synchro Discord type /sondage, boutons cœur inutiles, pas de durée obligatoire, votes site/Discord non liés.
  • Salon Discord 1509777735604502589 : message type /sondage (Components V2) avec en-tête # <@&1533535457508462612> | Titre, boutons vote gris, uniquement 🌐 + 🔗 (pas de ❤️/💔).
  • Votes MySQL + discord_id : même identité Discord/site = un seul votant (anti-doublon).
  • Site : durée obligatoire (presets) dans le composeur sondage ; sync Discord auto à la publication.
  • Bridge bot-public : /internal/forum/publish-poll + /internal/forum/poll-sync ; API interne site /api/internal/forum/poll-vote + poll-close.
  • Un vote Discord ou site (compte lié) se reflète des deux côtés sans doublon.
  • Fin de durée : clôture Discord + site.
  • web/src/lib/forum-poll.ts, forum-poll-votes.ts
2026-08-08 15:40 — Boutique : cards style capture + modal produits

### Contexte

Les CategoryCard renvoyaient vers /boutique/c/[slug] ; besoin d’un layout type capture (cover + titre + count + fourchette prix) et d’un modal produits.

### Changements

### Fichiers

shop-category.ts, api/shop/categories/route.ts, CategoryCard.tsx, CategoryProductsModal.tsx, boutique/page.tsx, boutique/c/[slug]/page.tsx

  • API catégories : maxPrice (MAX(price)).
  • CategoryCard : layout cover 16/10 + bandeau sombre, prix bleu min–max, clic onSelect.
  • CategoryProductsModal : Dialog grille ProductCard + recherche.
  • Hub /boutique : ouvre le modal ; deep link ?c=slug ; ?category= → ?c=.
  • /boutique/c/[slug] → redirect /boutique?c=slug.
2026-08-08 15:34 — Annonces Discord + transcripts tickets/logs

### Contexte / problème

1. Boutons d’annonces Discord colorés (vert/rouge/bleu) — demander gris.

2. Activation transcript tickets sans forcer l’événement logs ticket_transcript.

3. Format message annonce/actualité : manquait le ping rôle + titre en H1.

### Changements appliqués

### Impact

### Fichiers touchés

  • Boutons ❤️ / 💔 / 🌐 en style Secondary (gris) ; lien 🔗 reste Link.
  • En-tête message : # <@&role> | Titre puis corps — rôle annonce 1533535452240547840, actualité 1533535454861721620 ; allowed_mentions.roles pour le ping.
  • Toggle transcript tickets ON → logs.events.ticket_transcript = true + bucket tickets dans enabled_types.
  • Annonces/actus Discord : header + ping rôle + boutons gris.
  • Transcripts tickets visibles dans les logs dès activation côté tickets.
  • bot-site/src/lib/forumAnnouncementPost.js
2026-08-08 15:29 — Verify guilds : légal allégé + redirect + options IP/ISP

### Contexte / problème

### Changements appliqués

### Impact

### Fichiers touchés

  • Page /verify/{guildId} (ex. 1528492590683394078) exigeait le règlement Discord (réservé au serveur principal /commencer).
  • Après OAuth Discord, redirection forcée vers /commencer au lieu de rester sur /verify/{id} (succès/échec).
  • Manque d’options config vérif : multi-comptes/IP, FAI France only, autoriser 4G/5G.
  • Cases légales : hors serveur principal → CGU + mentions uniquement (requireReglement=false) ; cookie/API OAuth alignés.
  • Callback OAuth : succès → /verify/{guildId}?verified=1 (sauf guild principale → /commencer?step=prefs) ; erreurs déjà sur /verify/{id}.
  • Suppression du redirect client auto vers /commencer dans VerifyClient.
  • Config bot /config vérif : toggles Multi-IP, FAI FR, 4G/5G (+ persistance allow_same_ip_multi, french_isp_only, allow_mobile).
2026-08-08 15:00 — Vérif web : /commencer uniquement serveur principal

### Contexte

Panneau /config vérif web renvoyait tous les serveurs vers /commencer (parcours LB'XMB uniquement).

### Changements

### Fichiers

verificationPanel.js, panelsSecurity.js

  • Guild principale 1232966743241130005 → https://lbxmb.fr/commencer
  • Autres guilds méthode web → https://lbxmb.fr/verify/{guildId} (bouton lien « Me vérifier »)
2026-08-08 14:50 — Annonces forum : images + boutons réactions

### Changements

1. Images jointes au post forum envoyées en pièces jointes Discord (webhook multipart).

2. Plus de réactions emoji ; boutons sans texte : ❤️ vert, 💔 rouge, 🌐 bleu (traduction locale), 🔗 gris (lien post).

3. Compteurs -# ❤️ n · 💔 n sous le message ; vote toggle par utilisateur.

### Fichiers

forumAnnouncementPost.js, discordRest.js, forumWebTranslateHandler.js, interactionCreate.js, discord-bot-site.ts, thread/create/route.ts, bot-site/index.js

2026-08-08 14:40 — Messages présentation + règlement Discord

### Changements

### Fichiers

staticInfoPages.js, post-static-info.js, interactionCreate.js

### Hotfix annonces forum : pas d’intégration lien

  • Salon 1535574434683944980 : message présentation des salons (liste structurée) + bouton Translate (locale client, éphémère).
  • Salon 1490638171640434748 : règlement + même bouton Translate.
  • Handler static_info_tr:* + script scripts/post-static-info.js.
2026-08-08 13:20 — DM notifs annonces / actualités / sondages

### Contexte

DM trop verbeux + lien « gérer les rôles » ; besoin d’opt-out simple.

### Changements

### Fichiers

notifChannelDm.js, notifChannelDmHandler.js, interactionCreate.js

### Hotfix bot-public (chemin import notif DM)

  • Texte DM : Une nouvelle <#salon> a été publiée sur LB'XMB.FR
  • Bouton Ne plus m'informer → modal (taper CONFIRMER) → retire le rôle Discord notif ; bouton devient Je veux être informé (re-ajoute le rôle).
  • Appliqué à annonces, actualités, sondages (pas giveaway/sanctions/vidéos).
2026-08-08 13:00 — Forum Discord, boutique, notifs live, annonces

### 1. Miroir posts forum

### 2. Boutique forum Discord

### 3. Notifs Twitch/YT/GitHub/RSS

### 4. Annonces forum → Discord

### Fichiers

discord-site-forum-channels.json, siteForumSync.js, forumAnnouncementPost.js, forumWebTranslateHandler.js, libretranslate.js, notificationsModals.js, routerNotifications.js, youtube.js/streams.js/github.js/rss.js, notifMessage.js, thread/create/route.ts

2026-08-07 20:50 — Open Graph fiche produit boutique

### Contexte

Lien Discord /boutique/{id} : embed générique (layout liste) — pas le nom / icône / description du produit.

### Changements

### Impact

Embed Discord sur partage produit affiche titre, icône et description du produit.

### Fichiers

shop-product-og.ts, boutique/[id]/layout.tsx, shop/[id]/layout.tsx

  • Layout boutique/[id] + lib partagée : og:title = nom, og:image = icône produit (image/icon), og:description = description plain ; Twitter summary (vignette).
  • Alignement shop/[id] (redirect) sur le même contenu OG / canonical boutique.
2026-08-06 20:25 — Vérif OAuth : pipeline prochaines vérifications

### Contexte

Faux positifs audit OAuth + tokens non fiables ; sécuriser les prochaines vérifs (scopes, persist tokens, pas de revoke race).

### Changements

1. Callback vérif refuse si scopes incomplets (identify, guilds.join, relationships.read) ou sans refresh_token.

2. Upsert account obligatoire (échec → pas de vérif) ; refresh toujours écrasé (pas COALESCE silencieux).

3. Entrée verified_users : oauth_scope + oauth_linked_at ; clear revoked_at / revoke_reason ; drop des revoke_guild_web_verification en file pour ce membre.

4. Audit --apply exige aussi --force (webhook reste la source de vérité).

### Impact

Prochaine vérif via /commencer stocke une app OAuth complète ; re-vérif après retrait d’app ne se fait pas écraser par une commande revoke en attente.

### Fichiers

discord-oauth.ts, verify-oauth-callback-logic.ts, scripts/audit-verified-oauth.mjs

2026-08-06 20:10 — Profil Discord URL + vérif rôles légitimes

### 1. Pseudo Discord → URL /profil/...

### 2. Bot refile le rôle non-vérif aux légitimes

2026-08-06 19:40 — Boutique cards, forum Profil, reconcile vérif

### 1. Boutique : cards trop grandes

### 2. Forum recherche : bouton Profil

### 3. Bot : rôles vérif incohérents

2026-08-06 19:30 — Bot : /account owners, revoke OAuth, alerte amis blacklist

### 1. /account réservé owners

### 2. App Discord retirée → re-vérif

### 3. Blacklist → MP aux amis OAuth

### Note audit OAuth (rollback)

2026-08-06 19:15 — Forum : limite posts 2000 / 4000 VIP
  • Membres : 2000 caractères (texte brut hors markdown léger).
  • VIP Premium, VIP Booster, ancien slug vip : 4000.
  • UI compteur + blocage saisie + validation API thread/create alignés.
2026-08-06 19:07 — Forum : tags z-index, sidebar compacte, fond dalle

### 1. Menu tags (priorité d’affichage)

### 2. Sidebar sujets PC trop grande

### 3. Fond dalle / « établi » disparu

2026-08-03 20:40 — Fiabilisation accès salons `/commencer` & `/roles`

### Contexte

L’attribution ViewChannel sur les catégories console (overwrite membre) échouait parfois : rate-limits Discord mal gérés, retries faibles, succès UI même si des salons avaient échoué, IDs catégorie stale possibles.

### Changements appliqués

### Impact

### Fichiers

  • discordFetch : respect Retry-After / retry_after (429), retries 5xx / réseau.
  • applyCommencerChannelAccess : file globale (pas de courses multi-users), concurrence 2, 3 passages sur les échecs, retrait des overwrites des consoles désélectionnées, bits View+ReadHistory+Connect+Send+Speak.
  • Plus d’ajout d’ID catégorie absent du guild live.
  • APIs /api/commencer et /api/roles : échec explicite si des consoles sont choisies mais l’accès salon n’est pas complet ; passage de previousConsoles.
  • Test live : NES+PS4 → 10/10 overwrites en ~2 s.
  • bot-site redémarré + web-prod redéployé.
2026-08-03 19:45 — Votes communautaires 24 h + types élargis

### Contexte

Les votes /sanction n'expiraient pas. Le champ « type de sanction » devait devenir un type de proposition plus large (modo / partenariat).

### Changements appliqués

### Impact

### Fichiers

  • Expiration automatique des votes à 24 h (expiresAt, scheduler + filet 5 min) ; statut expired si pas de seuil atteint.
  • Champ renommé Type de proposition avec options : Timeout, Ban, Retirer modérateur, Ajouter modérateur, Retirer un partenariat.
  • Application rôles : Modérateurs (1532605771005558935), Partenaires (1307424700934258751) + MP « vote communautaire ».
  • Affichage du countdown de fin de vote sur le message ; durée (timeout/ban) toujours gérée séparément.
  • Une proposition sans 15 votes d'un côté expire sous 24 h sans effet.
  • Auto-nomination autorisée uniquement pour « Ajouter modérateur ».
  • bot-public/src/lib/moderation/communitySanctionStore.js
2026-08-03 19:16 — MP sanction : mention explicite du vote communautaire

### Contexte

Les sanctions appliquées via /sanction (TO/ban) n'affichaient pas clairement l'origine « vote communautaire » dans le MP (les extraLines n'étaient pas rendus dans le payload V2).

### Changements appliqués

### Impact

### Fichiers

  • notifySanctionMember / buildSanctionDmPayload : flag communityVote.
  • Titre MP : « Vous avez été … suite à un vote communautaire ».
  • Champ Origine = Vote communautaire (plus de mention du bot comme modo).
  • Détails + entrée store avec communityVote: true ; raison audit Discord déjà préfixée [Vote communautaire].
  • L'utilisateur sanctionné par le vote voit clairement que c'est une décision communautaire.
  • Les sanctions staff classiques (/ban, /to, …) sont inchangées.
  • bot-public/src/lib/moderation/sanctionNotify.js
2026-08-03 19:07 — Modération communautaire `/sanction` (vote)

### Contexte

Mise en place d'un système de proposition de sanction communautaire : modal /sanction, publication anonyme dans un salon de vote, décision à 15 votes « d'accord » ou « pas d'accord ».

### Changements appliqués

### Impact

### Fichiers

  • Nouvelle commande publique /sanction ouvrant une modale V2 (sélecteur de membre, type Timeout/Ban, raison, durée optionnelle).
  • Publication d'un container Components V2 dans le salon 1532747804852617216 sans afficher le proposant : membre ciblé, type, durée, raison + boutons vert/rouge.
  • Compteur de votes (1 vote / utilisateur, bascule possible) ; à 15 « Je suis d'accord » → application TO ou ban + MP sanction ; à 15 « Je ne suis pas d'accord » → rejet, pas de sanction.
  • Timeout : durée obligatoire (max 28j). Ban : durée vide = permanent. La cible ne peut pas voter sur sa propre proposition.
  • Persistance JSON data/moderation/community_sanctions.json + routage interactions cmsanc:*.
2026-08-03 15:22 — Suppression du `package-lock.json` obsolète (source de faux positifs de sécurité)

### Contexte

Après le correctif précédent, bun audit confirmait 0 vulnérabilité, mais npm audit continuait d'afficher 32 vulnérabilités (dont 1 "critical" sur better-auth, des CVE sur axios, hono, next, etc.) qui n'ont rien à voir avec l'état réel du projet. Repartagé par le signalant via le terminal pour vérification.

### Investigation

### Changements appliqués

### Impact

### Fichiers

  • web/package-lock.json datait du 1er mai 2026 (vs bun.lock mis à jour le jour même) : un fichier totalement gelé/obsolète depuis 3 mois, qui ne reflète ni les dépendances installées, ni les correctifs appliqués depuis (montée cap-widget, patchs de sécurité du jour, etc.).
  • Vérifié qu'aucun script, CI ou Dockerfile du projet ne référence package-lock.json (seules occurrences trouvées : un script interne à node_modules/@sentry/cli, sans rapport avec le workflow du projet).
2026-08-03 15:20 — Vraies failles de sécurité corrigées proprement (sans réintroduire le risque du rollback)

### Contexte

Après le rollback d'urgence (14:58), bun audit repassait de 34 à 18 vulnérabilités : le rollback avait annulé tous les correctifs de sécurité obtenus par bun update --latest, y compris ceux qui étaient légitimes (adm-zip, sharp). Signalé par le signalant en repartageant le terminal : "ya encore des soucis avec les paquets". Objectif : corriger les vraies failles de sécurité sans réintroduire les montées de version majeures et risquées (redis, bullmq, cookie, swiper, @socket.io/sticky, etc. — voir entrée 14:58, ceux-là restent volontairement sur leur ancienne version, aucun CVE ne les concernait).

### Investigation

### Changements appliqués

### Impact

### Fichiers

  • Confirmé au passage que npm audit est basé sur package-lock.json, un fichier obsolète depuis le 1er mai 2026 (le projet utilise bun/bun.lock, activement maintenu). Son rapport (32 vulnérabilités dont une "critical" sur better-auth) ne reflète pas les dépendances réellement utilisées en prod — à ignorer/considérer non pertinent tant que bun.lock est la source de vérité. (Cause probable de confusion : npm audit fix --force aurait pu écraser des choses sans rapport avec la réalité de l'app.)
2026-08-03 15:05 — Vraie cause du faux "vérification a échoué" trouvée : reset() systématique de Cap au démontage du widget

### Contexte

Après le fix du nonce CSP (entrée 14:44), le signalant confirme par capture d'écran que le message "La vérification a échoué ou a expiré." s'affiche toujours juste après un captcha résolu avec succès, et que l'utilisateur est quand même redirigé vers Discord OAuth juste après. Le fix précédent (nonce CSP pour l'instrumentation) était nécessaire mais ne couvrait pas cette cause-là, présente elle aussi depuis le début.

### Investigation

### Changements appliqués

### Impact

### Fichiers

  • Lecture du code source de cap-widget (node_modules/cap-widget/src/cap.js) : sa méthode disconnectedCallback() (appelée par le navigateur à chaque fois que l'élément <cap-widget> est retiré du DOM) appelle systématiquement this.reset(), qui déclenche un événement custom "reset" — que le retrait soit une vraie expiration ou un simple démontage React normal.
2026-08-03 14:58 — Rollback d'urgence : `bun update --latest` lancé à la main en prod pendant le fix Cap

### Contexte

Pendant le fix du captcha ci-dessus, un bun update puis un bun update --latest ont été lancés manuellement dans un terminal, directement dans ~/lbxmb.fr/web (le checkout de production, celui que deploy.sh build et déploie). bun update --latest ignore les contraintes semver de package.json et saute vers les toutes dernières versions, y compris majeures. Résultat : node_modules/bun.lock de prod se sont retrouvés avec des montées de version majeures et non testées juste avant qu'un deploy.sh (lancé pour livrer le fix Cap) ne rebuild et redéploie — livrant donc ces montées de version en prod sans validation :

| Paquet | Avant | Après (non désiré) |

|---|---|---|

| redis | 5.12.1 | 6.2.0 |

| bullmq | 5.81.3 | 6.0.6 |

| sharp | 0.34.5 | 0.35.3 |

| cookie | 1.1.1 | 2.0.1 |

2026-08-03 14:44 — Captcha Cap : "la vérification a échoué" au login malgré un captcha résolu + mise à jour Cap

### Contexte

Signalement : au login (bouton Discord), le captcha Cap (self-hosté, cap.lbxmb.fr) se résout visiblement bien côté utilisateur (case cochée / PoW calculé), mais le site affiche quand même l'erreur générique "La vérification a échoué ou a expiré." et bloque la connexion.

### Investigation

### Changements appliqués

### Impact

### Fichiers

  • Le widget cap-widget (npm, embarqué dans web/) était en version 0.1.53, la version publiée la plus récente étant 0.1.56.
  • Cap Standalone (conteneur Docker tiago2/cap:latest, web/cap/docker-compose.yml) tournait sur une image figée depuis le 24/05/2026 malgré le tag latest (Docker ne re-pull jamais tout seul une image déjà présente localement).
  • Cause racine identifiée (indépendante de la version du widget, présente dès la 0.1.53) : Cap Standalone active par défaut un "instrumentation challenge" (vérification anti-bot supplémentaire côté navigateur, en plus du calcul PoW). Ce challenge s'exécute dans une iframe srcdoc avec un <script> inline injecté dynamiquement par le widget. Notre CSP (script-src à base de nonce + 'strict-dynamic', sans 'unsafe-inline') bloque ce script inline car le site n'exposait jamais window.CAP_SCRIPT_NONCE / window.CAP_CSS_NONCE — variables que cap-widget sait utiliser pour propager le nonce CSP courant vers ses scripts injectés (mécanisme documenté, cf. https://trycap.dev/guide/widget.html et issue amont tiagozip/cap#229).
2026-08-03 14:40 — Résolution finale confirmée + upgrade Anubis 1.26.2 + nettoyage debug

### Contexte

Suite du fix 14:20 : le signalant a testé fix.html plusieurs fois sur son téléphone (confirmé dans les logs : hits successifs à 12:32, 12:34, 12:36, 12:37) et ça rebouclait quand même immédiatement après, avec exactement le même cookie techaro.lol-anubis-auth périmé (~20h, action: CHALLENGE, jamais une session validée) renvoyé à chaque requête. Un vidage manuel via Chrome > "Effacer les données de navigation" n'a pas non plus suffi dans un premier temps.

### Investigation complémentaire

### Changements appliqués

### Impact

### Fichiers

  • Version Anubis obsolète : 1.25.0 installée (paquet .deb local, hors dépôt apt) alors que 1.26.2 est disponible, avec des correctifs pertinents en amont (retries/robustesse de la page de challenge sur connexions instables type mobile, COOKIE_HTTP_ONLY, historique de bugs connus sur les doublons de cookies same-name/different-scope confondant le navigateur — issues GitHub TecharoHQ/anubis #520, #902, #1481). Mise à jour effectuée en production : téléchargement du .deb officiel GitHub Releases, dpkg -i, systemctl restart anubis@lbxmb, daemon-reload. Confirmé fonctionnel (anubis --version → 1.26.2) mais n'a pas suffi seul à débloquer le téléphone concerné (nouvelle boucle observée juste après le restart).
2026-08-03 14:20 — Réparation auto des navigateurs déjà bloqués (sans vidage manuel des données)

### Contexte

Le fix précédent (13:57) empêche le bug pour les nouveaux Service Workers, mais les visiteurs ayant déjà l'ancien Service Worker cassé en cache restaient bloqués : vérifié en live sur le téléphone du signalant (logs Anubis, IP stable 176.141.187.200, boucle de centaines de challenges/minute). Demande explicite : ne pas dépendre d'un vidage manuel des données par chaque membre de la communauté.

### Investigation

### Changements appliqués

### Impact

### Fichiers

  • Tentative kill-switch auto (échec) : déployé une version de sw.js qui se désinstalle elle-même à l'activation (self.registration.unregister() + reload des clients), en misant sur la vérification de mise à jour automatique du navigateur à chaque navigation. Surveillance en direct (journalctl -u anubis@lbxmb -f + tail -f access log) pendant que le signalant retestait en boucle sur son téléphone : aucune vérification de mise à jour ne se déclenche tant que la boucle de navigation tourne aussi vite (confirmé sur 90s / ~150 requêtes) → le navigateur ne récupère jamais le nouveau script tant qu'il est piégé. Cette approche est abandonnée.
2026-08-03 13:57 — Fix "Anubis charge à l'infini" (certains visiteurs bloqués tant qu'ils ne vident pas les données du site)

### Contexte

Signalement : depuis le passage du site derrière Cloudflare Tunnel (cloudflared sur un LXC Proxmox distinct) + Anubis (anti-bot Proof-of-Work), l'écran Anubis "Making sure you're not a bot!" reste bloqué en chargement infini pour une partie des visiteurs. Seul un vidage complet des données du site (cookies + storage + Service Worker) débloque temporairement le problème.

### Investigation

### Changements appliqués

### Impact

### Fichiers

  • Vérifié que le flux Anubis backend est sain : simulation complète (résolution du calcul PoW difficulty=2, appel /.within.website/x/cmd/anubis/api/pass-challenge, obtention du cookie techaro.lol-anubis-auth, re-requête sur / sans nouveau challenge) → 100% fonctionnel côté serveur.
2026-08-02 19:10 — Retrait rôle non-vérifié plus fiable (tous les cas)

### Contexte

Le rôle 1528010127691485205 restait pour certains malgré le log « retiré » (cache stale, auto-rôle permanent qui le redonne au rejoin, ack file même si échec).

### Changements

### Impact

Retrait systématique dès vérif + réparation auto si un cas glisse.

### Fichiers

  • Retrait avec force fetch + retries + vérif « encore présent ? »
  • File web : ne consomme pas la commande tant que le rôle est encore là
  • Rejoin vérifié : retire toujours non-vérifié (plus lié à onboarding_done)
  • Auto-rôles permanents : ne redonnent plus non-vérifié aux déjà vérifiés
  • Reconcile toutes les 5 min : strip non-vérifié des verified_users
  • bot-public/src/handlers/verification/verificationPanel.js
  • bot-public/src/handlers/verification/webVerificationQueue.js
2026-08-02 18:47 — Retrait rôle non-vérifié dès la vérif web

### Contexte

Après OAuth vérif, le rôle 1528010127691485205 restait (retrait différé jusqu’à Terminer).

### Changements

### Impact

Dès qu’un user valide la vérif Discord, le rôle non-vérifié est retiré tout de suite.

### Fichiers

  • webVerificationQueue : applyRoles: true à nouveau → retire remove_roles (non-vérifié) dès complete_guild_web_verification
  • Cleanup one-shot des membres déjà vérifiés qui avaient encore le rôle
  • bot-public/src/handlers/verification/webVerificationQueue.js
2026-08-02 18:45 — Accès catégories console + page règlement

### Contexte

1. Après validation consoles/notifs, plus d’accès aux catégories Discord.

2. /legal/reglement n’affichait pas le texte.

### Changements

### Impact

### Fichiers

  • Cause permissions : bot-site appelait discord.com → Cloudflare 1015 ; listGuildChannels / overwrites échouaient (channelAccess ok: false)
  • bot-site → API Canary (https://canary.discord.com/api) comme bot-public
  • Scope live des 31 catégories ; IDs mapping confirmés (PS5, Switch 1&2, Xbox One & Series, etc.)
  • Fallback résolution par nom de catégorie si ID manquant
  • /api/roles retire aussi le rôle non-vérifié avant overwrites
  • Page règlement : retrait Framer Motion (opacity:0 SSR) → contenu visible sans hydratation JS
  • Terminer / /roles peut à nouveau poser ViewChannel sur catégories + salons console
  • Notifs (Annonces, Actu…) = rôles Discord + DM bot (inchangé)
2026-08-02 18:25 — Expulsion auto si non vérifié sous 24h

### Contexte

Les membres qui rejoignent sans se vérifier restaient indéfiniment avec le rôle non-vérifié.

### Changements

### Impact

Sans vérif sous 24h → expulsion + possibilité de revenir via l’invite.

### Fichiers

  • Scheduler unverifiedKickScheduler : toutes les 5 min, membres avec rôle non-vérifié + pas d’entrée vérifiée (ou verification_revoked) + arrivée ≥ 24h → DM puis kick
  • DM : non vérifié → expulsé + lien https://discord.gg/j4nGqnb7yZ
  • Config vérif : kick_unverified_enabled / hours / invite (activé sur le serveur LB'XMB)
  • Bouton panneau sécurité « Kick 24h : ON/OFF »
  • Exemptions : bots, owners bot, owner guild, Admin / Manage Guild
  • bot-public/src/handlers/verification/unverifiedKickScheduler.js
  • bot-public/src/lib/securityConfig.js
  • bot-public/src/events/client/ready.js
2026-08-02 18:22 — Terminer rôles : plus de faux blocage « IP déjà créée »

### Contexte

Après vérif Discord, « Terminer » (config rôles) renvoyait « Un autre compte a déjà été créé depuis cette adresse IP ».

### Changements

### Impact

La finalisation des rôles ne passe plus par le garde « 1 IP = 1 compte ».

### Fichiers

  • checkCommencerIpGate(..., { skipUniqueAccount: true }) sur POST /api/commencer (utilisateur déjà vérifié)
  • userKey normalisé (user_id numérique / discord_id) pour l’enregistrement IP
  • web/src/lib/ip-tracking.ts
  • web/src/app/api/commencer/route.ts
2026-08-02 18:05 — /roles + DM notifs + fix IP replace

### Contexte

1. Besoin d’une page pour gérer rôles sans refaire /commencer.

2. DM bot sur publications (annonces, actu, giveaway, sondage, sanction, vidéo).

3. Après acceptation remplacement IP : bloqué / IP encore vue comme prise.

### Changements

### Salons → notifs

### Fichiers

  • Page /roles + API /api/roles (auth Discord, consoles + 6 notifs)
  • Rôles Discord recréés (Annonces/Actualités/Sondages/Sanction/Vidéo) + Giveaway existant
  • Handler messageCreate → DM membres du rôle lié au salon
  • findOtherAccountWithIp ignore verification_revoked
  • Strip IP plus agressif + DM post-accept → https://lbxmb.fr/roles
  • annonces 1378803099212447754
  • actualité 1348035878920126545
  • giveaway 1431225812710981764
  • sondage 1509777735604502589
  • sanction 1532747804852617216
2026-08-02 17:50 — IP replace bouton + rôles + salons Terminer

### Contexte

1. /commencer ip_taken : pas de bouton pour demander le remplacement.

2. Autoriser IP : l’ancien compte devait récupérer non-vérifié ; le nouveau le perdre.

3. « Terminer » : salons/rôles pas toujours appliqués (POST plantait avant Discord sur Truncated DECIMAL).

### Changements

### Impact

Flux remplacement IP actionnable ; Terminer plus robuste pour les accès salons.

### Fichiers

  • Bouton « Demander le remplacement de compte » sur /commencer (ip_taken)
  • OAuth : plus d’auto-queue ; demande uniquement via le bouton
  • Autoriser : nouveau = retire non-vérifié ; ancien = redonne non-vérifié + verification_revoked
  • /api/commencer POST : Discord (rôles/salons) avant SQL ; UPDATE via discord_id ; retries channel-access
  • web/src/app/commencer/page.tsx
  • web/src/app/api/commencer/route.ts
2026-08-02 17:42 — Autoriser / Refuser remplacement IP

### Contexte

Les échecs ip_taken apparaissaient dans /vérification mais sans demande pending → pas de boutons. Cause : callback OAuth live (verify-oauth-callback.cjs) ne créait pas d’entrée dans ip-share-requests.json.

### Changements

### Impact

Staff peut traiter les remplacements IP depuis /vérification → menu Remplacer le compte.

### Fichiers

  • CJS OAuth : queueIpShareReplaceRequest à chaque ip_taken (+ notif échec avec other_id)
  • Section « Remplacer le compte » : boutons Autoriser / Refuser
  • Après action : panneau rafraîchi (reste sur la section) + bannière résultat
  • Backfill pending depuis les échecs ip_taken récents (résolution other via config serveur)
  • web/lib/verify-oauth-callback.cjs
  • bot-public/src/commands/moderation/verification.js
  • bot-public/src/handlers/verification/verificationPanel.js
  • bot-public/src/handlers/verification/webVerificationQueue.js
2026-08-02 17:35 — Panneau /vérification Discord : menu déroulant

### Contexte

Container V2 unique trop dense (réussites + échecs + IP + ISP + blobs enc:v1).

### Changements

### Impact

UX admin lisible ; IP déchiffrées pour le staff.

### Fichiers

  • /vérification : menu StringSelect (Réussites / Échecs / Remplacer compte / Ajouter opérateur)
  • Une section à la fois + boutons d’action dans la section
  • IP admin affichées en clair via revealIp (plus de blob chiffré)
  • Handler verify:admin:nav dans interactionCreate
  • bot-public/src/commands/moderation/verification.js
  • bot-public/src/events/interaction/interactionCreate.js
2026-08-02 17:27 — Pack vérif / guides / hero / perms / DECIMAL / RGPD

### Contexte

Liste multi-sujets : acceptation légale + règlement, IPs chiffrées, guides README GitHub, hero 2 lignes, faux erreur captcha, suppression RGPD, cache permissions, erreur MySQL DECIMAL à la vérif.

### Changements

1. Vérif : version cookie légal 2026-08-02 + rappel règlement dans les checkboxes ; page règlement à jour

2. Mentions légales : section AES-256-GCM / HMAC pour IPs ; /legal/rgpd → redirect mentions ; liens Footer/Login/CGU nettoyés

3. Guides : GET renvoie markdown/github ; guideId alias create ; fix JSX + icône GitHub ; import README inchangé mais affichage réparé

4. Hero : LA RÉFÉRENCE / DU MODDING en 2 lignes (toujours flex-col)

5. Cap : ignore erreurs post-solve ; Anubis COOKIE_PARTITIONED=false

6. Auth cache : staleTime:0 + refetch focus ; dashboard re-check 60s/focus

7. DECIMAL : users-lookup.ts + commencer/auth/me ; fallback auth-helpers ne met plus d’UUID dans user_id

2026-08-02 17:17 — Whitelist ISP : Cogeco Connexion (Canada / Québec)

### Contexte

Vérif refusée isp_denied pour « Cogeco Connexion inc » (Québec). Demandes pending dans isp-requests.json.

### Changements

### Impact

Match Cogeco Connexion inc → OK (CA). Relancer la vérif Discord devrait passer côté opérateur.

### Fichiers

  • Ajout Canada → Cogeco Connexion (/\bcogeco\b/i) dans web/lib/allowed-isps.cjs
  • 2 demandes ISP Cogeco marquées approved
  • pm2 restart web-prod (reload du module CJS)
  • web/lib/allowed-isps.cjs
  • data/verify/isp-requests.json
2026-08-02 16:51 — cloudflared installé et connecté

### Contexte

Token tunnel fourni ; sortie via IP Proxmox .62 bloquée en HTTPS → default route basculée sur LAN 192.168.1.1.

### Changements

### Impact

Tunnel Healthy côté connecteur. Reste à publier les hostnames → http://127.0.0.1:8080 et supprimer les A vers .62.

### Note

Default route LAN non persistée au reboot (à figer dans la conf réseau CT).

  • Installé cloudflared 2026.7.3 (deb GitHub)
  • Service systemd cloudflared enabled + running
  • Tunnel ID cb79de95-… connecté (cdg*, QUIC OK)
  • Warning temporaire : pas encore d’ingress dashboard → 503 jusqu’aux Published application routes
2026-08-02 16:47 — Discord API Canary (contournement 1015)

### Contexte

discord.com renvoie Error 1015 (rate-limit CF) depuis l’IP FAI → bot offline + login OAuth invalid_code. canary.discord.com / ptb.discord.com répondent 200.

### Changements

### Impact

### Fichiers

  • bot-public : REST https://canary.discord.com/api (src/lib/discordApi.js, Client principal + secondaire + deploy-commands)
  • web : rewrite fetch dans server.js (Better Auth) + URLs canary dans libs/routes Discord + instrumentation.ts + CSP
  • Override possible : DISCORD_API_BASE
  • bot-public reconnecté : Connecté en tant que LB'XMB.FR#3591 (10 guilds), health ready:true
  • Login Discord site : échange token via canary (patch runtime server.js)
  • bot-public/src/{index.js,deploy-commands.js,lib/discordApi.js,lib/secondaryBot.js}
  • web/server.js, web/src/instrumentation.ts, web/src/lib/discord-api-base.ts, libs/routes Discord, web/lib/verify-oauth-callback.cjs
2026-08-02 16:33 — Préparation Cloudflare Tunnel (origine locale)

### Contexte

Objectif : exposer la CT via cloudflared (LAN) sans dépendre de l’IP tunnel Proxmox 151.240.100.62.

### Changements appliqués

### Impact

### Fichiers

  • nginx : écoute locale 127.0.0.1:8080 (HTTP) en plus du 4443 PROXY protocol — origine pour le tunnel
  • map X-Forwarded-Proto pour respecter le proto Cloudflare Tunnel
  • Fichiers : infra/cloudflared/config.example.yml, install-from-token.sh
  • Bloqueur : pas d’HTTPS sortant depuis la CT → binaire cloudflared non téléchargeable pour l’instant
  • Origine tunnel prête : http://127.0.0.1:8080
  • Reste : installer le binaire + token Zero Trust + DNS CNAME tunnel (pas d’A vers .62)
  • /etc/nginx/sites-enabled/lbxmb.fr, actp, game, pterodactyl
  • infra/cloudflared/*
2026-08-02 16:19 (heure locale serveur / UTC 14:19) — Upload chunké 95 MiB (proxy Cloudflare)

### Contexte / problème

Le proxy Cloudflare Free bloque les requêtes > ~100 Mo. Les uploads (cloud, ZIP ressources, staff-chat, etc.) partaient en un seul POST multipart et échouaient au-delà. Pas de tunnel cloudflared (stack nginx + orange cloud conservée).

### Changements appliqués

### Impact visible / technique

### Fichiers touchés

  • Protocole chunks partagé : POST /api/uploads/chunks (init) → PUT …/[id] (Content-Range) → POST …/complete → champ chunkUploadId / chunkUploadId_* sur l’endpoint métier.
  • Taille chunk : 95 MiB ; TTL sessions 24h sous uploads/_chunks/.
  • Helper serveur resolveFormUpload / expandChunkFieldsInFormData branché sur cloud, ressources, staff-chat, shop, guides, tickets, profil, chat, forum, projects, vendor, shared-games, etc.
  • Helper client chunked-upload-client.ts (uploadFileWithChunks, prepareFormDataWithChunks) branché sur les UIs d’upload.
2026-08-02 16:14 — nginx :8080 exposé sur le LAN (fix 502 tunnel)

### Contexte

Tunnel global (autre CT) pointe vers http://192.168.1.112:8080 → Cloudflare 502 car nginx n’écoutait que 127.0.0.1:8080 (connection refused depuis le LAN).

### Changements

### Impact

### Fichiers

  • Remplacé listen 127.0.0.1:8080 → listen 8080 (0.0.0.0) dans sites-enabled : lbxmb.fr, actp, game, pterodactyl (+ copies sites-available)
  • Backups déplacés hors de sites-enabled (/etc/nginx/backups-lan8080/) pour éviter duplicate upstream
  • systemctl restart nginx (reload insuffisant pour changer le bind)
  • Doc exemple tunnel : origine LAN 192.168.1.112:8080
  • ss : 0.0.0.0:8080 LISTEN
  • http://192.168.1.112:8080 joignable ; https://lbxmb.fr → HTTP 200 via Cloudflare
  • Curl sans CF-Connecting-IP → Anubis 500 (attendu) ; avec header CF → 200
  • /etc/nginx/sites-enabled/{lbxmb.fr,actp.lbxmb.fr.conf,game.lbxmb.fr.conf,pterodactyl.conf}
2026-08-01 23:03 — Chiffrement IPs + compte désactivé + boutique qty + responsive 1340 + guides + upload 413

### 1. Chiffrement IPs at-rest (AES-256-GCM)

### 2. Compte désactivé (libc + flux contestation)

### 3. Quantité boutique

### 4. Responsive ≤1340px = mobile

### 5–6. Guides : chapitrage latéral + icônes OS

### 7. Upload 413 (fichiers ~190 Mo)

  • Passphrase IP_ENCRYPTION_PASSPHRASE (web + bot)
  • Format enc:v1:… + ip_hash HMAC pour lookups
  • Migration : user_ips / ip_visits / ip_intel / JSON guildes
  • Admin : spoiler masqué + bouton « Déchiffrer / révéler »
  • Bot /account : déchiffre puis spoiler Discord ||ip||
  • Réactivation desactive=0 pour libc.prx
2026-08-01 21:55 — /vérification (plus de DM) + fix perms consoles
  • Notifications vérif en DM trop bruyantes
  • Après « Terminer » onboarding, ViewChannel user non appliqué sur catégories/salons
  • Stop DM admin / demandeur (succès, échecs, IP replace, ISP)
  • Journal web/data/verify/admin-inbox.json + lecture pending IP/ISP
  • Commande slash /vérification (éphémère Components V2) : réussites, échecs, boutons Remplacer/Refuser & Ajouter opérateur
  • Sanitize audit reason latin1 dans discordRest.js
  • Restart bot-site / bot-public
2026-08-01 21:45 — Post-vérif → /commencer (choix rôles)
  • Callback .cjs : lit next du state ; succès → /commencer?step=prefs&verified=1 (ou next si fourni)
  • Miroir TS + filet client VerifyClient : redirect auto vers /commencer si verified=1
  • Restart web-prod pour charger le .cjs
2026-08-01 21:40 — Fix DM Remplacer IP manquant
  • Toujours enfiler ip_share_request si absent de la file (même pending existant)
  • Un seul DM admin pour IP prise (refus + Remplacer/Refuser), plus l’alerte séparée
  • Relance manuelle de la demande pending → DM envoyé
2026-08-01 21:35 — Vérif onboarding : 1 clic, IP replace, opérateur simple
  • « Me vérifier » → Discord OAuth direct (plus de /verify intermédiaire)
  • Erreurs OAuth → retour /commencer (si onboarding)
  • IP déjà liée : demande auto + DM uniquement 1139951514694193323 avec Remplacer / Refuser
  • Opérateur : 1 bouton « Ajouter mon opérateur » → DM admin Ajouter l’opérateur / Refuser
  • Alertes refus ISP/IP : plus de DM spam au demandeur ni aux autres owners
2026-08-01 21:20 — /commencer : toujours recommencer (vérif → rôles → Terminer)
  • Plus de court-circuit onboardingDone → done
  • Connecté sans verified=1 → étape vérification obligatoire (IP/ISP)
  • Prefs uniquement après retour OAuth vérif (verified=1)
  • Callback login Discord → ?step=verify (plus step=prefs)
2026-08-01 21:15 — Invitation Discord expirée remplacée
  • Remplacement par invite permanente active j4nGqnb7yZ (salon accéder-au-serveur)
  • Fallbacks + NEXT_PUBLIC_DISCORD_INVITE_URL mis à jour
2026-08-01 19:11 — Onboarding Discord unifié (Commencer → vérif → Terminer)

### Sous-entrée A — Panneau Discord

### Sous-entrée B — Rôles différés jusqu’à Terminer

### Sous-entrée C — Parcours web /commencer

  • Remplacement du panneau « Me vérifier » (méthode web) par accueil Commencer (lien /commencer) + Traduire (LibreTranslate + ?lang= sur le lien)
  • Style bouton Commencer = Link (contrainte Discord URL)
  • applyMemberVerification(..., { applyRoles: false }) après vérif web / IP-share
  • Restore au rejoin : rôles seulement si verified_users[].onboarding_done === true
  • Phases : landing → login Discord → needVerify → prefs (consoles par marque + Annonces/Actualités/Giveaway/Sondages) → Terminer
  • OAuth vérif accepte next (retour /commencer?step=prefs)
  • POST Terminer : retire non vérifié 1528010127691485205, assigne notifs (dont giveaway 1533097995015553126), ViewChannel catégories console, marque onboarding_done
2026-08-01 11:03 — ISP whitelist : Tunisie Telecom + Starlink
  • Entrées TN Tunisie Telecom + XX Starlink (SpaceX) dans BASE_ALLOWED_ISPS
  • Labels UI : Tunisie / Autres · Satellite
2026-08-01 00:20 — Join serveur : token bot manquant côté web
2026-08-01 00:00 — Persistance token OAuth à la vérif (guilds.join)
  • Upsert account (access/refresh/scope) dès l’échange OAuth vérif
  • Lien better_auth_user_id à la création compte site
  • Message d’erreur join plus clair + refresh avant check scope
2026-07-31 23:55 — /account amis & join : secret + URL site
  • INTERNAL_API_KEY du bot ≠ secret attendu par web-prod → HTTP 401 « Non autorisé »
  • BOT_SITE_URL pointait vers http://127.0.0.1:8787 (bot-site) au lieu de https://lbxmb.fr
  • Alignement secrets bot ↔ web ; BOT_SITE_URL=https://lbxmb.fr
  • account.js / friends.js : résolution URL qui ignore localhost ; priorité BOT_INTERNAL_SECRET
2026-07-31 23:50 — Fix scopes OAuth (virgules Better Auth)
  • parseOAuthScopes / oauthScopeHas (virgules + espaces)
  • Checks relationships.* et guilds.join corrigés
  • Refresh token plus robuste si access token absent/expiré
2026-07-31 20:45 — Orange = France Télécom + pas d’IP en DM user
  • Patterns Orange FR : france télécom / wanadoo
  • ip-api vérif : champs org, as, asname (AS3215 Orange S.A.)
  • DM refus utilisateur : plus d’IP ni d’ISP (staff conserve IP/ISP)
  • DM succès staff : affiche l’opérateur whitelisté (isp_match)
2026-07-31 20:35 — ISP refusé : IP soulignée + DM tentative
  • Redirect OAuth isp_denied (et ip_taken / blacklist) inclut ip=
  • Page /verify : IP affichée soulignée sous le message « Opérateur non autorisé »
  • File bot verify_attempt_notify → DM staff (owner) + DM à l’utilisateur ayant tenté
2026-07-31 17:55 — Fix membres vérif + persist vérif + actions /account

1. Page /verify affichait -51 membres (Discord approximate_member_count négatif)

2. Retrait de l'appli Discord / rejoin annulait de facto la vérif (rôles non réappliqués)

3. /account sans actions rapides staff

### 1. Compteur membres

### 2. Persistance vérification

### 3. /account — actions rapides

  • Au guildMemberAdd, si présent dans verified_users → applyMemberVerification (rôles restaurés)
  • verified_at conservé au restore
  • Dissociation OAuth site Discord ne nullifie plus discord_id / discord_verified
2026-07-31 17:45 — Compte auto + rôle blind + fix IP 127.0.0.1

1. Créer un compte site à chaque vérif (si absent)

2. Rôle 1528010127691485205 ne doit plus voir aucun salon

3. /account / vérif ne doivent plus accepter/afficher 127.0.0.1

  • ensureSiteAccount dans le callback TS (CJS l’avait déjà) — create-if-missing
  • Vérif refusée si IP non publique (loopback/privée) — CJS + TS
  • mergeIpHistory ignore les IPs privées/loopback
  • Nettoyage JSON : 39 entrées verified_users sans 127.0.0.1
  • /account filtre les IPs junk
  • Sync overwrites : rôle non vérifié → ViewChannel: false sur tous les salons (appliqué immédiatement sur LBXMB)
2026-07-31 17:34 — /account + vérif translate + salons + IP coexistence

### 1. /account

### 2. Sync IPs vérif ↔ site

### 3. Translate panneau Discord

### 4. Config vérif — rôles + salons

### 5. IP déjà utilisée — coexistence

2026-07-31 17:17 — Nouvelle invitation Discord serveur (site)
  • Défaut DISCORD_INVITE_URL → https://discord.gg/hZH5jCszN (web/src/lib/discord.ts)
  • Fallback apps/services → même URL (web/src/lib/applications-links.ts)
  • NEXT_PUBLIC_DISCORD_INVITE_URL ajouté dans web/.env.local
  • Fallback bot-site (config.js, activity.js, .env.example) alignés
  • Remplacement in-place dans .next-staging + restart web-prod / bot-site
2026-07-31 17:01 — Fix interactions Garde d'arrivées (panneau Protection)
  • Branchement cfg:sec:joins, cfg:sec:jg:toggle, cfg:sec:jg:edit dans routerSecurity.js
  • Modal seuils cfg:sec:jg:modal:joins + submit dans securityModals.js
  • Role select exempt cfg:sec:jg:exempt:roles reconnu et persisté via patchRegularization
2026-07-31 16:40 — Warn-kick immédiat + vérif ISP mondiale

1. Campagne « Je veux rester » : garder les ~200 keepers, expulser le reste pour inactivité

2. Vérification Discord : ne plus se fier au résidentiel ; whitelist FAI mondiale + 1 IP / compte

### 1. Warn-kick — expulsion forcée

### 2. Vérification — ISP only + IP

### Bilan kick (fin de pass)

  • expiresAt forcé dans le passé sur la tâche active (wk_5da664af…)
  • Pass d’expiration lancé (DM + kick hors keepers / bots / owners)
  • Raison kick + DM : « Vous avez été expulsé pour inactivité. Vous auriez dû appuyer sur le bouton Je veux rester pour ne pas être expulsé. »
  • Whitelist FAI 24 pays (Orange/SFR/Bouygues/Free FR, opérateurs DE/UK/ES/IT/BE/NL/CH/PT/PL/US/CA/MX/BR/CN/IN/JP/KR/ID/MA/EG/ZA/AU/TR…)
  • Hors liste → vérification refusée (reason=isp_denied)
  • 1 IP = 1 compte Discord ; conflit → reason=ip_taken
  • Re-vérif : ajoute l’IP (max 2 IPs distinctes, pas de remplacement aveugle)
2026-07-23 09:28 — Blacklist DM, signalements, activité, anti-rejoin

1. Blacklist sans MP → pas de bouton Contester

2. /signalement : bouton Whitelist à la place d'Ignorer ; besoin Sanctionner / Ignorer

3. /config : section Activité du serveur (régularisation)

4. Anti-raid : boucle leave/rejoin

### 1. Blacklist — DM avant ban

### 2. /signalement — Sanctionner / Ignorer

### 3. /config → Activité du serveur

### 4. Anti leave/rejoin

  • Boutons Sanctionner + Ignorer (plus Whitelist)
  • Menu : Avertissement (raison) ou Blacklist (durée vide = permanente + raison)
  • MP pour warn et blacklist ; ignore = ferme uniquement le signalement
  • Hub conditions (offline, messages, réactions, interactions, vocal min), délais, grâce, invite, rôles exemptés
  • Garde d'arrivées (plafond + rafale → kick + MP + invite)
  • bot-site lit la config guilde ; délai expulsion_delay_days avant kick
2026-07-22 20:56 — Sanctions V2 + panneau /blacklist
  • DM ban/kick/to/warn/mute/blacklist en Components V2 (container + thumbnail serveur, accent #a0000a)
  • Bouton Contester (1×) sur ban, warn, blacklist uniquement → owner serveur (ban/warn) ; blacklist = stocké sans MP owners
  • /blacklist sans options → panneau : Ajouter / Retirer / Liste / Contestation
  • Blacklistés peuvent toujours cliquer Contester malgré le gate global
2026-07-22 16:55 — Fix restauration rôles + pseudos au retour

1. saveAutoRolesOnLeave existait mais n’était jamais appelé au GuildMemberRemove

2. Au leave, Discord n’envoie plus nick/rôles si le membre n’est pas en cache → sauvegarde vide

  • Wiring saveAutoRolesOnLeave + saveNickOnLeave sur leave
  • Store member-snapshots mis à jour à chaque guildMemberUpdate / join
  • Warm snapshots au démarrage (guild.members.fetch) si restauration active
  • Leave : fallback snapshot si cache vide
  • Logs role-restore / nick-restore leave+join
2026-07-22 16:40 — Fix /to (contestable) + restauration pseudo au retour

1. /to plantait : Cannot access 'contestable' before initialization

2. Besoin d’une option config pour restaurer le pseudo serveur après départ/retour

  • sanctionNotify.js : contestable déclaré avant usage
  • Pseudos auto : option hub Restaurer le pseudo au retour (restore_nickname_on_rejoin)
  • Au GuildMemberRemove : sauvegarde du nickname serveur
  • Au retour : restauration prioritaire (sinon règles permanentes/temporaires)
  • Plus de save incorrect à l’arrivée après application d’un format
2026-07-21 22:55 — Warn-kick DM : boutons Translate + Je veux rester
  • DM envoyés en embed + composants : Translate et Je veux rester
  • Relance file pour non-keepers (nouveau format)
2026-07-21 22:45 — Warn-kick : salon DM corrigé + panneau Translate + relance
  • Fermeture de la campagne invalide (mauvais salon)
  • Lien DM forcé vers 1528633918280962179
  • File DM reconstruites : 1216 membres (78 keepers exclus)
  • Panneau renvoyé avec Translate + Je veux rester (msg 1529227086114459850)
  • API POST /warn-kick/panel et POST /warn-kick/resend-dms
  • Skip keepers dans la campagne DM + lock anti double-rebuild
2026-07-21 22:10 — /commencer : onboarding obligatoire après Discord
  • Flux : landing → Discord → toujours écran onboarding (consoles + notifs) → succès seulement après « Terminer la configuration »
  • Plus de skip via onboardingDone en base
  • Retry session si cookie OAuth pas prêt (step=prefs)
  • Copie onboarding claire (« Choisis tes rôles ») ; succès = « Configuration terminée » + lien modifier
2026-07-21 19:09 — Signalements blacklist + /commencer permissions catégories + panneau

### 1. Blacklist / signalements

### 2. /commencer — accès salons par catégories

### 3. Panneau Commencer Discord

  • guildMemberAdd : re-ban immédiat si isBlacklisted
  • Signalements : liste filtrée status=open ; bouton Whitelist ferme les reports ouverts
  • Blacklist depuis report : deferReply, propagation relations, ferme reports ouverts, meilleurs détails d’erreur ban
  • /blacklist remove + contestation acceptée : ferment aussi les reports ouverts
  • Log si échec save() blacklist
  • Mapping console → category ID (commencer-categories.ts / commencerCategories.js)
  • bot-site POST /commencer/channel-access : overwrites membre (View + ReadHistory + Connect) sur catégorie + salons enfants
  • API web POST /api/commencer appelle channel-access après assignation rôles
2026-07-21 09:01 — Warn-kick / Commencer : Translate FR→FR
  • Locale fr : réponse éphemère « Ce message est déjà en français. » (pas d’appel LibreTranslate)
  • Autres locales : message d’erreur clair si traduction KO ; plus de content: null
  • Même correctif sur le panneau Commencer
2026-07-21 08:42 — Warn-kick : liste « Je veux rester » + masquage salon (overwrite membre)
  • Sur chaque keep : deny ViewChannel utilisateur sur le salon (pas @everyone)
  • Sync rétroactive des keepers déjà inscrits (~60)
  • API POST /warn-kick/keepers + POST /warn-kick/sync-hide
  • Commande Discord /warn-kick-list (staff autorisé)
  • Message keep : confirmation + salon masqué
2026-07-20 20:09 — Deploy web-prod (prefs + IP beacon)
2026-07-20 20:06 — /commencer : prefs consoles/notifs + IP v4/v6 auto
  • Landing accueillante inchangée → après OAuth : étape prefs (consoles + notifs) → succès
  • getClientIps / normalizeIp renforcés (IPv6 brackets, XFF split)
  • POST /api/commencer : recordIpVisits sur toutes les IP détectées (is_registration_ip)
  • Création compte (auth-helpers) : IP enregistrée en registration
  • Nouveau POST /api/ip-beacon + appel auto dès l’étape prefs
2026-07-20 20:04 — Fix IP client (PROXY protocol) — erreur /commencer « IP introuvable »
  • Stream : proxy_protocol on vers backends nginx (4443/4444/4446)
  • Strip PROXY avant coturn (13478/15349)
  • listen … proxy_protocol sur les vhosts HTTPS
  • Map $real_client_ip : CF-Connecting-IP si présent, sinon $proxy_protocol_addr
2026-07-20 19:57 — Deploy web-prod (commencer accueillant)
  • deploy.sh OK — BUILD_ID VYQmMg2D-Z1Oej6ciZegt ; web-prod redémarré
2026-07-20 19:55 — /commencer : landing accueillante, sans rôles
  • Landing chaleureuse (fonds verts/ciel, logo, animations douces) + message d’accueil
  • Explication claire : intégration simple au serveur + vérification anti-abus
  • Suppression de l’UI consoles / notifications / rôles
  • Après OAuth Discord : finalisation auto via POST (rôle membre si configuré)
  • Écran succès + lien invite Discord réel
2026-07-20 19:37 — Deploy web-prod (/commencer landing)
  • bash deploy.sh : build Next → swap .next-staging → pm2 restart web-prod --update-env
  • BUILD_ID GjriZ843iuwRG-rEez0Ih ; 5 workers cluster online
2026-07-20 19:31 — /commencer : landing manuelle + layout large
  • Suppression de l’auto-redirection Discord au chargement
  • Landing d’accueil avec présentation LB'XMB.FR + bouton Commencer (OAuth au clic)
  • Layout élargi (max-w-5xl), plus aéré ; grille consoles 3 colonnes en prefs
2026-07-20 13:02 — Photos de profil : URLs fiables + sync OAuth propre
  • getPhotoUrl renforcé + isLocalUploadPhoto / buildDiscordAvatarUrl
  • OAuth Discord : mapProfileToUser pose name + image CDN ; sync photo sans écraser Profils/ ; sync aussi sur liaison Discord legacy
  • /api/auth/me : COALESCE users.photo → Better Auth user.image + heal si vide
  • APIs online / featured-home : photos normalisées via getPhotoUrl
  • UI chat/forum/projects/vocal/dashboard/donate : plus de /uploads/ brut pour les avatars
  • nginx : rewrite /uploads/ → /api/uploads/ (prod + ptb)
  • Heal DB : images Better Auth resynchronisées depuis users.photo quand vides
  • Deploy web-prod
2026-07-20 12:36 — Redirections post-Discord selon le parcours
  • /login → callback / (plus de double OAuth via discord-complete)
  • discord-complete : simple redirect vers next ou / (compat)
  • User Install bot : retour /discord/bot?installed=1 via cookie API
  • /commencer : inchangé (/commencer?step=prefs après Discord)
  • Verify : déjà /verify/{guild}?verified=1 (page succès)
2026-07-20 12:23 — OAuth Discord login : User Install uniquement (plus de sélecteur de guild)
  • Login Better Auth : integration_type=1 forcé, suppression de guild_id / permissions
  • buildDiscordAuthorizeUrl : toujours User Install, jamais de guild_id
  • Verify + link : alignés sur le même flux compte
2026-07-20 12:13 — /warn-kick : fix 404 (BOT_SITE_URL)
  • Défaut BOT_SITE_URL → http://127.0.0.1:8787 dans warn-kick.js et warnKickPanel.js
  • Ajout BOT_SITE_URL + INTERNAL_API_KEY dans bot-public/.env ; restart --update-env
2026-07-20 12:03 — /warn-kick : rôle staff `1232966884375265281` autorisé
  • warn-kick ajouté à SKIP_GUILD_ACCESS (contourne le garde mod générique)
  • Accès autorisé si utilisateur 1139951514694193323 ou rôle 1232966884375265281 (bot-public + bot-site)
  • Config serveur LB'XMB : permissions warn-kick avec ce rôle + loupblanke en user
2026-07-20 11:52 — /warn-kick : bypass garde modération Discord
  • /warn-kick n'utilise plus modSlash : commande standalone avec contrôle uniquement sur l'ID 1139951514694193323
2026-07-20 11:35 — /warn-kick : réservé loupblanke + DM all avec rate-limit
  • Commande /warn-kick et API POST /warn-kick/start : réservées à l’ID 1139951514694193323
  • Campagne DM d'avertissement persistante (warnKickDmCampaign.js) : 1 DM / 2 min, pause 20 min tous les 30 DM
  • État campagne stocké dans state.json (queue, index, batch) — survit aux redémarrages
  • Message DM d'avertissement distinct du message d'expulsion finale
2026-07-20 11:27 — /warn-kick : Translate n’affiche que l’embed (sans composants)
  • warn-kick handler Translate : suppression de components dans la réponse traduite (l’embed reste traduit, le message original conserve les vrais boutons).
2026-07-20 11:25 — /warn-kick : commande rendue visible + Translate conserve boutons
  • Ajout de warn-kick dans bot-public/src/lib/serverConfig.js (DEFAULT_COMMANDS) pour qu’elle soit synchronisée sur les guilds.
  • warn-kick handler Translate : édition du message en conservant components (boutons restent visibles/clickables).
2026-07-20 11:04 — /warn-kick : précision expiration (scheduler toutes les 10 min)
  • Scheduler bot-site /warn-kick passe de 1h à 10 min (exécution plus rapide après expiresAt).
2026-07-20 11:03 — /commencer : UI épurée (groupes + icônes) + redirection auto
  • Groupes UI explicites : Nintendo, PlayStation, Xbox, Autres (liste basée sur RESOURCE_FORM_CONSOLES)
  • Ajout d’icônes console via imageId (/api/consoles/images/<imageId>.png)
  • Auto-redirection OAuth Discord dès que /api/commencer renvoie authenticated=false (sauf cas error=oauth)
2026-07-20 11:03 — OAuth Discord : pré-sélection guild LB'XMB.FR (suppression prompt “choisir un serveur”)
  • BetterAuth (login Discord) : ajout de guild_id dans l’URL OAuth générée
  • User Install : ajout de guild_id dans les URLs integration_type=1
2026-07-20 11:03 — /warn-kick : régularisation 45 jours persistante + liste “Je veux rester” + DM + Translate
  • Création de la commande /warn-kick (bot-public) : envoie un message avec boutons Je veux rester (vert) + Translate
  • Translate (bot-public) : traduit le contenu de l’embed via LibreTranslate selon la locale Discord (bouton non expirant)
  • Etat persistant (bot-site) : stockage sur data/warn-kick/state.json des tâches + liste keepers + expiration
  • Scheduler (bot-site) : toutes les heures, kick des non-keepers à expiresAt, avec DM explicatif (lien vers le salon de commande)
  • Clic Je veux rester : envoi au bot-site pour ajouter l’utilisateur à la liste ; période fermée ensuite
2026-07-20 05:51 — Discord-only + /commencer + panneau salon
  • Login Discord uniquement ; providers Google/GitHub retirés de Better Auth
  • Section « Comptes associés » retirée du profil
  • Soft-delete de 49 comptes sans discord_id
  • Scopes unifiés : identify guilds.join relationships.read applications.commands (messages.read exclu)
  • Page /commencer + API : intro → OAuth → consoles/notifs → rôles Discord
  • Garde IP : VPN/proxy/hosting/mobile + whitelist Orange/Free/Bouygues/SFR + 1 IP = 1 compte
  • Panneau salon 1528633918280962179 (Translate + lien Commencer) via bot-site ; handler Translate dans bot-public
2026-07-19 19:20 — Switch Online + mods multi-jeux optionnels
  • Catégorie Online ajoutée pour Nintendo Switch et Switch 2
  • Jeu optionnel pour les mods (plus de validation bloquante)
  • Sélection multi-jeux (jusqu’à 12) : structure.json.jeux + colonne jeux_json, jeu = premier pour chemins/compat
  • Filtres / sidebar / détail tiennent compte de tous les jeux liés
2026-07-19 19:01 — Sync releases : Gitea / Forgejo (hors GitHub)
  • Parseur d’URL : hosts arbitraires, suffixe /releases ignoré, page org (1 segment) résolue via API
  • Client releases : GitHub + Gitea/Forgejo (/api/v1), User-Agent anti-Anubis
  • Sync / autofill / téléchargement d’assets branchés sur ce client
  • Libellés UI FR/EN mis à jour ; alerte si dépôt sans assets de release
2026-07-19 18:05 — Musique : bot secondaire, busy, vote skip
  • resolveVoiceBot : si le principal est occupé ailleurs (musique/radio/record) → secondaire ; si les deux occupés → busy + message
  • connect musique/radio : refuse de réutiliser une connexion d’un autre salon
  • /play, /playlist, /radio, lecteur : refus explicite si bots déjà utilisés
  • /skip + bouton ⏭️ : vote majoritaire des humains du vocal (skip immédiat si seul)
2026-07-19 13:13 — Sync variantes : clés uniques AppImage
2026-07-19 13:10 — Sync GitHub : détection OS assets (win_/AppImage)
2026-07-19 12:55 — Sync GitHub : support format variantes (Chiaki)
  • Sync télécharge les assets puis réécrit variantes via buildVariantesFromGithubAssets (chemins locaux sous releases/{tag}/)
  • Noms d’affichage telechargements = nom d’asset courant (plus de nom figé)
2026-07-19 11:12 — Vocal temporaire : ordre boutons corrigé
2026-07-19 11:08 — Vocal temporaire : couleurs + grille 2×4
  • Grille 2 lignes × 4 boutons (Modifier · Limite · Invité · Expulsé / Accès · Perms · Transférer · Récupérer)
  • ➕ Invité = vert (Success), ➖ Expulsé = rouge (Danger), Transférer + Claim = bleu (Primary)
2026-07-19 08:56 — Fix OAuth state_mismatch (www vs apex)
  • Cookies Better Auth crossSubDomainCookies domain .lbxmb.fr
  • Nginx : www.lbxmb.fr → 301 https://lbxmb.fr
  • Proxy Next + composant client : redirection www → apex
  • Message login : affiche aussi state_mismatch s’il est dans l’URL
2026-07-18 21:55 — Fix OAuth : relationships.write invalide
2026-07-18 21:00 — Fix OAuth Discord invalid_scope (messages.read)
2026-07-18 20:26 — Vocal temporaire : nouvelle image légende
  • Asset assets/tv-legend.png (et .jpg) remplacé par l’image fournie.
  • Boutons Discord réordonnés en grille 4×2 alignée sur la légende (✉️ pour Transférer).
2026-07-18 20:16 — CSP : plus de warnings strict-dynamic
2026-07-18 18:53 — UX Minecraft : hub, /mc-server, console
2026-07-18 18:14 — Whitelist IP : scan à la seconde
2026-07-18 18:03 — Whitelist IP : réaction plus rapide
  • Intervalle scan 2,5 s (premier scan ~0,8 s).
  • list + kick sur une seule session RCON.
  • Messages Discord non bloquants ; cache des guilds whitelist ON.
2026-07-18 17:42 — Whitelist IP : plus de RCON Minecraft
  • Templates ipwhitelist / whitelist+{ip} / mcipwhitelist → stockent dans la DB bot (addMcIpWhitelist), sans commande RCON.
  • Config serveur mise à jour + entrée .Jessybarden0710 / 88.163.181.14 migrée.
  • Placeholder /config custom boutons : mcipwhitelist add {pseudo} {ip}.
2026-07-18 17:35 — Whitelist IP : scan joueurs déjà connectés

### Fix : config minecraft ignorée au chargement

  • Scan RCON list à l'activation + toutes les 20s si whitelist ON → kick les pseudos non autorisés.
  • Message console Discord pour chaque kick.
2026-07-18 17:10 — Whitelist IP : toggle + kick via console
  • Flag minecraft.ip_whitelist_enabled (défaut OFF) — toggle dans /config → Minecraft (Whitelist IP : ON/OFF) et /mcwhitelist.
  • Autorisation si IP ou pseudo listé ; sinon kick Vous n'êtes pas whitelist discord.gg/lbcs.
  • Parse des lignes console (Steve[/ip:port] logged in…) via API /internal/minecraft/console + messages du salon console Discord → kick RCON.
2026-07-18 13:40 — OAuth : messages + MP + commandes (2 étapes)
  • Étape 1 login : identify + relationships.write + guilds.join + messages.read (sans integration_type).
  • Après session → /auth/discord-complete → User Install applications.commands + integration_type=1 (MP + créer commandes).
  • Verify : scopes login (token user), plus User Install seul.
2026-07-18 13:32 — Fix crash bot-public (imports mcBridge) + /friends
  • Imports corrigés vers ../../lib/....
  • /friends ajouté aux PUBLIC_COMMANDS.
  • Bot redémarré (API /health OK, 8 guilds).
2026-07-18 13:25 — Fix OAuth : 0.0.0.0 + invalid_scope

1. Redirect erreur utilisait request.url origin → https://0.0.0.0:25581 (hostname d'écoute Next).

2. Scopes User Install (messages.read + integration_type=1 + relationships.write) → invalid_scope.

  • Redirects OAuth → toujours BETTER_AUTH_URL / https://lbxmb.fr.
  • Login : identify + relationships.write + guilds.join sans integration_type.
  • User Install bot : identify + applications.commands + integration_type=1 (séparé).
2026-07-18 13:19 — Demande d'ami auto à l'autorisation Discord
2026-07-18 13:16 — Whitelist IP MC, console bridge, vérif perms, tickets, /friends

### Whitelist IP Minecraft (par serveur Discord)

### Miroir console Minecraft → Discord

### Vérification — overwrites salons

### Tickets — séparateur ・

### /friends

2026-07-18 13:06 — OAuth Discord : login + verify alignés

### Connexion cassée / callbacks Discord

  • Scopes User Install unifiés (comme le générateur Discord) : identify + applications.commands + messages.read + guilds.join + relationships.write + integration_type=1.
  • Login BetterAuth → https://lbxmb.fr/api/auth/callback/discord (redirectURI explicite).
  • Vérification → https://lbxmb.fr/api/verify/oauth/callback (authorize + token exchange).
  • Erreurs Discord (invalid_scope, etc.) redirigées vers /login?error=oauth avec error_description (évite « State not found » opaque).
  • HEAD sur callback auth → 200 (sondes portail Discord).
2026-07-18 06:26 — Fix /config + logs Tickets

### /config cassé

### Logs — bucket Tickets

  • Nouveau bucket tickets + événements : ouverture, prise en charge, staff ajouté, fermeture, verrouillage, réouverture, transcript (fichier HTML joint).
  • sendGuildLog accepte des pièces jointes.
  • « Créer la structure » crée seulement les salons/posts manquants (ex. salon Tickets) sans tout recréer.
2026-07-18 06:21 — Minecraft RCON V2 (provider + commandes + console)

### Connexion API/RCON — liste de providers

### Commandes dédiées /mcwhitelist et /mc-player

### Salon console bidirectionnel

### Infos + Paramètres serveur

  • Sync guild uniquement si RCON Minecraft est prêt (activé + provider + identifiants).
  • /mcwhitelist : modal pseudo + IP optionnelle *(plugin ipwhitelist)*.
  • /mc-player : liste en ligne → panneau joueur (cœurs, faim, XP, inventaire, kick/ban/clear, gamemode, TP joueur ou coords).
2026-07-18 06:03 — RCON Minecraft + boutons commandes custom

### /config → Connexion API / RCON

### Commandes custom — boutons modal → RCON

  • Nouvelle section home « Connexion API/RCON » : activer, éditer hôte/port/mdp, tester, salon journal, joueurs, infos (seed/temps/list), exécuter une commande console.
  • Client rcon-client ; sorties optionnellement miroirées dans un salon Discord (pas de stream console live — RCON = requête/réponse).
  • Éditeur commande : format simple/container/embed, Liste RCON (rcon_prefetch → {rcon_result}), Ajouter bouton (label, titre modal, 1–2 champs, templates RCON une ligne = une commande).
  • Runtime : boutons ccmd:act: ouvrent un modal ; chaque ligne RCON ne s’exécute que si ses {variables} sont remplies (ex. pseudo seul → whitelist add, IP seule → ipwhitelist add).
2026-07-17 23:56 — Légende image fournie + Logs setup clarifié

### Vocal temporaire — image légende utilisateur

### Logs — UX structure

  • Instructions en 4 étapes + bouton dédié « Créer la catégorie + salons » / « Créer le forum + posts ».
  • setupLogsStructure active automatiquement les logs si besoin.
  • Affiche les salons/posts liés par catégorie une fois créés.
2026-07-17 23:36 — Légende Twemoji + structure Logs

### Légende vocal temporaire — emojis nets

### Logs serveur — structure catégorie / forum

  • Schéma logs aligné Python : type text|forum, enabled_types, channels / threads, category_id / forum_id.
  • UI : Activer · bascule Mode · Créer la structure · toggles catégories + événements fins.
  • sendGuildLog route vers le salon/thread du bucket (join, message, vocal, server, moderation, verification, antiraid) ; fallback legacy channel_id.
2026-07-17 22:56 — Config retours / Logs / Légende vocal

### Retours /config → accueil unifié

### Logs — échec d'interaction

### Légende vocaux temporaires

  • Tous les hubs (admin, logs, notifs, profil, rôles, etc.) → cfg:nav:home (nouveau panneau select).
  • Suppression page Admin catégorie + menu « Changer de catégorie » + ancien panels.js inutilisé.
  • Anciens liens nav:page:* / home:nav redirigés vers l'accueil.
2026-07-17 22:05 — Config / Signaler / TempVoice / Sécurité

### 1. /config — panneau d'accueil unifié

### 2. /signaler + menus contextuels unifiés

### 3. Panneau vocaux temporaires

### 4. Sécurité — pause invitations & MP inconnus

  • Accueil = container accent coral (#ff5e5b) + texte « Panneau de Configuration » + select « Configurer une option ».
  • 15 options (messages, rôles, pseudos, traduction, threads, tempvoice, tickets, stats, réactions, inter-salon, logs, protection, notifications, commandes, profil bot) avec descriptions corrigées.
  • Routing cfg:home:feature vers les panels existants.
  • Fix bug c → container sur Giveaways/Logs de la page Admin.
  • Modal unique (Labels V2) : select raison + description (obligatoire si « Autre ») + File Upload (jusqu'à 5 fichiers).
  • /signaler, App → Signaler (user) et Signaler (message) utilisent le même modal.
  • Oui : Discord permet désormais d'importer des pièces jointes dans un modal (FileUpload).
2026-07-17 11:45 — Bot offline après reboot VM

### Cause : crash bot-public au démarrage

  • Fix SyntaxError: Export 'WELCOME_VARIABLE_HELP' is not defined dans panelsV2.js (ré-export sans import).
  • Restauration DISCORD_TOKEN vide dans .env racine (cassait aussi bot-python / API Discord site) + sync bot/config.json.
  • start_bot.sh : ignore un DISCORD_TOKEN vide pour ne pas masquer config.json.
  • pm2 restart bot-public + pm2 save (autostart reboot déjà via pm2-root.service).
  • bot-python laissé stopped (même application Discord que bot-public → conflit de session).
2026-07-15 11:15 — Tickets : fermeture supprimer ou verrouiller

### Mode de fermeture configurable

  • Option À la fermeture dans /config → Tickets : supprimer (comportement actuel) ou verrouiller (lecture seule).
  • Mode verrouiller : retire l'écriture pour tout le monde, conserve le salon/thread.
  • Bouton Fermer devient Réouvrir quand le ticket est verrouillé.
  • Guard messages bloque toute écriture sur ticket verrouillé.
  • Un ticket verrouillé ne bloque plus l'ouverture d'un nouveau ticket par le même membre.
2026-07-15 11:10 — Fix tickets : UserSelectMenuBuilder
2026-07-15 09:10 — Sondage : date de fin obligatoire

### Durée / fin de sondage requise

  • Champ Durée obligatoire dans la modale « Question / description » (30m, 2h, 1d…).
  • Publication bloquée sans durée valide (min. 1 min, max. 30 jours).
  • Affichage de la fin sur le sondage publié + clôture automatique à l'échéance.
  • Reprise des timers au redémarrage du bot.
2026-07-15 08:50 — Fix config tickets bloquée (/config)

### Éditeur tickets ne répondait plus

  • Boutons compacts (2 rangées) à la place de 7 sections lourdes.
  • Sous-page Types / menus pour supprimer des types et gérer les menus section.
2026-07-14 22:10 — Backup : panneaux, stats dynamiques, communauté, remap config

### Republication panneau tickets à la restauration

### Statistiques serveur dynamiques (rôles / membres)

### Paramètres communauté dans la backup

### Config /config adaptée au nouveau serveur

  • Comptage via role.members.size.
  • Remap role_id, channel_id et placeholders {role.member.count:ID} dans les templates.
  • Reset last_applied à la restore ; recalcul forcé (force: true).
2026-07-14 21:55 — Fix backup : crash cache + ordre rôles

### Crash à la création (reading 'cache')

### Ordre des rôles inversé à la restauration

  • Filtre des salons sauvegardables (catégories, texte, vocal, forum… — pas les threads).
  • Sérialisation overwrites avec permissionOverwrites?.cache.
  • Fetch salons + garde-fous membres / @everyone.
  • Création des rôles du plus haut au plus bas (hierarchy_rank desc).
  • Réordonnancement via hierarchy_rank relatif (bas → position 1, haut → sous le bot).
2026-07-14 21:40 — Tickets boutons opt-in + Signaler message (clic droit)

### Tickets : boutons complémentaires activables

### Signaler un message (menu contextuel)

  • Prise en charge et Ajouter un staff désactivés par défaut — à activer dans /config → Tickets.
  • Toggle séparé pour « Ajouter un staff » (nécessite prise en charge activée).
  • Clic droit sur un message → Signaler → modale (contexte obligatoire).
  • /signalement affiche : contenu intégral, auteur, signaleur, lien, PJ, explication.
  • Loader commandes corrigé pour menus User + Message même nom.
2026-07-14 21:35 — Sondage votants, retour containers, tickets avancés

### Sondage : participants et détail des votes

### Boutons Retour containers

### Tickets : prise en charge + ajouter staff

### Tickets : template nom salon + reset menus

  • Bouton Prendre en charge (seul le staff assigné écrit).
  • Menu Ajouter un staff après prise en charge.
  • Mode staff non assigné : masqué (perd accès) ou lecture seule (configurable).
  • Guard messages pour threads/salons.
  • Template {ticket.emoji}, {user.id}, {date}, etc. (comme vocaux temp).
  • Config via /config → Tickets → Modifier (template nom).
  • Menus déroulants du panneau réinitialisés après sélection.
2026-07-14 21:10 — Fix /giveaway (commande unique + sync Discord)

### /giveaway sans sous-commandes

### Sync commandes Discord cassée

2026-07-14 20:48 — Rôles action, tickets avancés, /giveaway, stats, profil, forum scroll

### Rôles par action : retrait si statut retiré

### Tickets : staff, menus section, transcript, couleurs boutons

### Commande /giveaway

### Statistiques serveur : renommer + texte affiché

### Photo profil site

### Forum : scroll sujets

  • Rôles staff = seuls rôles avec accès (salon catégorie ou thread privé).
  • Interface Menus par section (jusqu'à 5 menus × 25 options).
  • Transcript HTML à la fermeture.
  • Couleur bouton via style=success dans description du type.
2026-07-14 20:08 — Tickets dans Système automatique (/config)

### Module tickets absent de /config

  • Section 🎫 Tickets ajoutée dans /config → Système automatique.
  • Config multi-panneaux : activation, types de tickets, mode threads/catégorie, interface boutons/menu, embed, publication du panneau.
  • Runtime : ouverture ticket (thread ou salon), bouton fermer, permissions staff par type.
  • Schéma tickets dans serverConfig (compatible structure Python configurations).
2026-07-14 19:46 — Sondage, admin poll/giveaway, stats serveur, fix démarrage bot

### bot-public : crash au démarrage (import LibreTranslate)

### /sondage : boutons alignés sur les choix

### /config Administration : sondages + giveaways

### Statistiques serveur (gstats) : options simplifiées

  • Section Sondages : rôles/utilisateurs autorisés à lancer et clôturer ; rôle ping à la publication.
  • Section Giveaways : permissions création / participation (prête pour /giveaway).
  • Schéma serveur : poll, giveaway dans serverConfig.
  • /sondage respecte les permissions config (lancer, clôturer, ping rôle).
  • Cibles : Nom du serveur ou Nom d'un salon vocal.
  • Statistiques : utilisateurs, bots, salons, rôles, membres avec rôle (sélecteur rôle si besoin).
  • Compteurs {channel.count} et {role.count} ajoutés au moteur.
2026-07-14 19:05 — Forum → Discord (bot-site), tags, /config sécurité

### Annonces forum → Discord (#annonces)

### Forum : menu tags (mobile Dialog)

### bot-public /config : dropdown Notifications

  • bot-site : POST /forum/announcement-post — webhook nom/avatar auteur, embed contenu, réactions 👍❤️👎, thread « Commentaire », menu traduction.
  • Mapping forum_sync_mapping.json mis à jour.
  • Web : appel direct bot-site au lieu de commands.json.
  • bot-public : handler forum_web_tr:* pour traduction éphémère (LibreTranslate).
2026-07-14 17:20 — Fix Stripe donate + traduction forum

### Stripe Checkout : automatic_payment_methods rejeté

### Traduction manquante forum.catAnnounce

2026-07-14 15:30 — Ressources, bot vocal, Stripe, profil, forum, messagerie

### Cheat Code sur toutes les consoles

### Tools : sous-catégorie Store

### Bot Discord : /stop + doublons vocal

### Stripe : moyens de paiement Dashboard

### Photo de profil invisible après upload

### Forum : scroll sidebar sujets

### Messagerie PC plein écran

  • resolveVoiceBot : réutilise le bot déjà dans le salon ; secondaire uniquement si enregistrement actif.
  • /stop : arrêt musique + radio sur les deux groupes (stopAnyMusic + stopAnyRadio).
  • musicManager.connect : réutilise getVoiceConnection existante.
2026-07-13 19:30 — UI mobile : messagerie, navbar, changelogs, paramètres

### Changelogs ressources : markdown Discord

### Mobile : z-index panneaux vs header

### Navbar : texte LB'XMB.FR mobile

### Paramètres : pays / langue en boucle

### Messagerie mobile : composer, menus, bottom nav

  • FloatingMessagePanel : bottom: 0 en conversation, 4rem en liste.
  • MessageComposerBar : padding réduit en mode embedded mobile.
  • Menu contextuel mobile : z-[10060]/[10061].
  • openMobilePanel() : un seul panneau (messagerie / notifs / profil / recherche).
  • Bottom nav masquée en conversation (onInConversationChange).
2026-07-13 13:10 — Fix connexion Discord : invalid_scope

### OAuth Discord rejeté par l'API (invalid_scope)

  • Login User Install : scopes identify + applications.commands uniquement (integration_type=1).
  • errorCallbackURL → /login?error=oauth + affichage error_description.
2026-07-13 12:55 — Login Discord : URL User Install unique (prod)

### Connexion site + applications.commands en un seul OAuth

  • Plugin BetterAuth discordUserInstallLoginPlugin : force integration_type=1, scopes identify+relationships.write+applications.commands+guilds.join, prompt=consent, URL discord.com/oauth2/authorize.
  • Suppression enchaînement post-login (PostLoginDiscordUserInstall).
2026-07-13 12:40 — Fix connexion Discord + permission « créer des commandes »

### Session site cassée par enchaînement OAuth trop rapide

  • Login Discord : callbackURL = / (session créée d'abord).
  • Flag lbxmb_post_login_user_install + composant PostLoginDiscordUserInstall : attend getSession() puis redirige vers User Install.
  • User Install : prompt=consent pour afficher « créer des commandes » (applications.commands).
  • /auth/discord-complete : simple redirect / (rétrocompat).
2026-07-13 12:25 — Connexion Discord : enchaînement User Install

### Flux login → User Install automatique

  • Après connexion Discord BetterAuth, redirection vers /auth/discord-complete puis /api/auth/discord/user-install (lien applications.commands + integration_type=1, redirect /discord/bot).
  • Cookie lbxmb_user_install_return + retour accueil après callback OAuth User Install.
  • Login API prod : scopes identify+guilds.join+relationships.write (sans applications.commands).
2026-07-13 12:10 — OAuth User Install, i18n, SW, actualités accueil

### Discord : login vs User Install

### Service Worker

### Traductions

2026-07-13 11:50 — Lot correctifs prod (scam, login, mobile, ressources)

### Attrape-scam : DM avant ban

### Connexion Discord cassée

### Mobile : drawers ressources/forum + menu hamburger

### Ressources : tri + import GitHub

2026-07-13 06:45 — Régularisation : tracking participation élargi
  • Clarification : sondages, réactions, messages, vocal, rôles d'accueil et commandes bot doivent compter comme participation.
  • recordParticipationFromInteraction : slash, menus contextuels, boutons, selects, modales.
  • Vocal (bumpMemberVoice) : annule aussi le compteur « jamais interagi » + règle 6 mois.
  • Rôles d'accueil : réactions + boutons/select cfg:rolepick déjà couverts.
  • Un membre actif sur le serveur (même sans message) n'est plus considéré inactif sur le critère interaction s'il passe en vocal ou utilise une commande.
  • bot-public/src/lib/memberActivity.js
  • bot-public/src/events/interaction/interactionCreate.js
  • docs/RECAP-TRAVAIL-COMMUNAUTE-2026-04.md
2026-07-13 06:40 — Régularisation Discord : correction expulsion massive (~600 kicks)
  • Passage automatique bot-site a expulsé ~600 membres avec l'ancienne logique (30 j « full » ou 90 j partiel en OU).
  • Règles attendues : expulsion uniquement si toutes les conditions sont remplies après 3 mois ; exception 6 mois en ligne sans activité ; compteur hors ligne reset à la reconnexion ; guilde 1232966743241130005 seule.
  • evaluateMemberInactivity v2 : AND (hors ligne 90 j + jamais message + jamais réaction + jamais bouton/menu) OU exception en ligne 180 j sans activité.
  • memberActivity.js (bot-public) : offline_since, pending_*_since, tracking_started_at ; présence reset offline ; réactions + interactions composants trackées.
  • Guilde forcée REGULARIZATION_GUILD_ID=1232966743241130005 ; membres sans tracking_started_at ignorés (pas de rétroactif).
  • Config : REGULARIZATION_STANDARD_DAYS=90, REGULARIZATION_ONLINE_IDLE_DAYS=180.
  • Plus d'expulsion en masse sur critères trop larges ; compteurs repartent au prochain événement présence/activité par membre.
2026-07-13 01:20 — Changelogs, nav droite, Discord user install, login 👋, modal DL, accueil interverti
  • Changelogs : entrées récentes en bas de page (scroll long).
  • Fiche ressource : colonne droite (télécharger / actions) ne restait pas visible au scroll.
  • Connexion Discord : flux guild install (ajout bot serveur) au lieu de user install.
  • Login : emoji main CDN (waving-hand) affiché en texte.
  • Modal téléchargement : regroupement auto exe→Windows, etc.
  • Accueil : interverti absent à côté de Default.xex (featured-home filtrait user_id avec des IDs Discord).
  • /changelogs : tri par date décroissante (plus récent en haut).
  • ResourceDetailClient : aside droite lg:sticky lg:top-24.
  • OAuth login Discord → /api/auth/discord/user-install (integration_type=1).
  • Login : emoji Unicode 👋 (plus de dépendance CDN Apple emojis).
2026-07-13 00:55 — Ressource Xbox multi-plateforme + fichier vs URL (Xb Homebrew Vault)
  • Ressource « Xb Homebrew Vault » (Xbox One + Series) : étiquette console n’affichait que Xbox One ; bouton « Visiter » grisé au lieu de « Télécharger ».
  • Cause : catégorie « Site » ajoutée par erreur (basculage URL / GitHub) alors que les fichiers sont hébergés localement ; isSiteResource traitait Tools+Site comme ressource site.
  • Données corrigées (resource_id 218) : retrait de « Site » dans categories_by_console_json + structure.json.
  • isSiteResource : ignore la catégorie Site si des téléchargements locaux existent ; helper stripSiteCategoryUnlessUrlOnly à l’ajout.
  • Fiche détail : fusion consoles déclarées + téléchargements ; libellés getPlatformDisplayName (Xbox One · Xbox Series X/S).
  • Liste ressources : consoles multiples affichées avec noms lisibles.
  • Formulaire ajout : mode Fichier retire la catégorie Site ; sync GitHub ne force plus le mode URL.
  • Xb Homebrew Vault téléchargeable via modale ; Xbox One et Series visibles sur la fiche et dans les listes filtrées.
2026-07-13 00:45 — Web : ressources, boutique, OAuth, staff, cloud, GitHub

### 1. Compteur ressources PS3 (45 vs 42)

### 2. Boutique profil

### 3. OAuth Google / GitHub

### 4. Chat staff — messages vocaux

### 5. Logs Discord staff

### 6. Page /cloud

### 7. Accueil — créateurs

### 8. GitHub repo (ajout ressource)

### Fichiers

  • Cause : sidebar comptait les ressources multi-catégories plusieurs fois.
  • Fix : décompte distinct resource_id par plateforme dans /api/resources/structure.
  • Composant partagé ProductCard (taille profile, grille plus dense).
  • Liaison unifiée via link-social (profil + paramètres).
  • Finalisation POST /oauth-providers/link au retour Google/GitHub.
  • Sync photo OAuth à chaque session.
2026-07-12 23:35 — Traduction : embeds et containers V2

### Contexte

### Changements

### Fichiers

### Impact

  • Les commandes /translate, menu « Translate this message » et bouton auto-traduction renvoyaient du texte brut, même pour les messages en embed ou container Components V2.
  • Module translateMessageLayout.js : détecte embed/container, traduit chaque bloc de texte (titres, sections, boutons, champs embed…), reconstruit le layout Discord traduit avec le footer de traduction intégré.
  • Branchement dans translate.js et autoTranslationHandler.js ; repli sur texte simple si pas de structure.
  • bot-public/src/lib/translateMessageLayout.js
  • bot-public/src/commands/util/translate.js
  • bot-public/src/handlers/autotranslation/autoTranslationHandler.js
  • docs/RECAP-TRAVAIL-COMMUNAUTE-2026-04.md
  • Traduction visuelle fidèle pour containers (help, invite, panels…) et embeds classiques.
  • Redémarrer bot-public.
2026-07-12 23:10 — Régularisation communauté (inactivité)

### Contexte

### Règles

### Changements

### Fichiers

### Impact

  • Expulser (kick, pas ban) les membres totalement inactifs sur le serveur LB'XMB, avec MP avant expulsion et lien de réinvitation.
  • 30 jours : aucun message, vocal, sondage et connexion (online/idle/dnd) → expulsion.
  • 90 jours : aucun message, vocal ni sondage (statut en ligne ignoré) → expulsion.
  • Grâce 14 jours après l'arrivée sur le serveur ; bots et owners bot exemptés ; rôles exemptés via REGULARIZATION_EXEMPT_ROLES.
  • bot-public : index d'activité partagé data/member_activity/<guildId>.json (messages, vocal, sondages /sondage, présence en ligne).
  • bot-site : évaluation quotidienne (~03:15 Paris), MP d'expulsion puis kick, log data/regularization/kicks.json, route manuelle POST /regularization/run (auth x-api-key).
  • bot-public/src/lib/memberActivity.js
  • bot-public/src/events/message/messageCreate.js
2026-07-12 22:05 — Bot : config custom, invite, help, contestations

### 1. Commandes personnalisées

### 2. /invite-bot

### 3. /signaler

### 4. Ajout bot sur serveur

### 5. Contestations ban/blacklist

### 6. /base64

### 7. /help

### 7b. /help — menu déroulant par catégorie

### Fichiers

  • Création : nom uniquement → bouton Configurer (message + rôles/utilisateurs).
  • Suppression du choix public/éphémère ; autorisations dans la config ; scope serveur inchangé.
  • Réponse visible (non éphémère) ; boutons Ajouter au serveur + Ajouter à mon compte ; container features.
  • Raison Autre → modale obligatoire pour préciser.
  • MP container au propriétaire (merci, /help, /config, features).
  • Une contestation par sanction ; owner serveur reçoit DM + bouton Débannir ; user prévenu avec lien d'invitation si accepté.
2026-07-12 21:25 — Alerte vocal → MP (serveur commun)

### Contexte

### Changements

### Fichiers

### Impact

  • Quand 1139951514694193323 rejoint ou change de salon vocal, alerter 1398073346175926272 en MP avec le lien du vocal — uniquement si les deux sont sur le même serveur.
  • Module voiceJoinAlert.js : détection voiceStateUpdate, vérif membre commun via guild.members.fetch, lien https://discord.com/channels/{guild}/{channel}, cooldown 45 s par salon.
  • bot-public/src/lib/voiceJoinAlert.js
  • bot-public/src/events/guild/voiceStateUpdate.js
  • docs/RECAP-TRAVAIL-COMMUNAUTE-2026-04.md
  • bot-public à redémarrer.
2026-07-12 21:15 — OAuth Discord étendu + blocage relations blacklist

### Contexte

### Changements

### Fichiers

### Impact

  • Besoin d'un lien OAuth unique (identify, applications.commands, guilds.join, relationships.write) pour login, liaison, vérification et User Install.
  • Lors d'une blacklist bot : bloquer l'utilisateur pour tous les comptes Discord ayant autorisé l'application ; prévenir la personne avec la raison et comment se débloquer dans les paramètres Discord.
  • Module central discord-oauth.ts : scopes + builders d'URL (login, liaison, vérification, User Install).
  • Better Auth Discord, prepare-link, /api/verify/discord/authorize, page bot : scopes étendus + integration_type=1 où pertinent.
  • Module discord-relationships.ts : blocage/déblocage via API Discord relationships.write (refresh token, parcours table account).
  • API interne POST /api/internal/discord/blacklist-relationships (bot → site).
  • Commande /blacklist : appelle la propagation relations à l'ajout/retrait ; MP mis à jour (raison + déblocage via Paramètres utilisateur → Bloqués).
2026-07-12 21:00 — bot-public : /userinfo et /serverinfo (User Install en guild)

### Contexte

### Cause

### Changements

### Fichiers

### Impact

  • Sur un serveur, /userinfo → Cannot read properties of null (reading 'members') ; /serverinfo → « Impossible de charger ce serveur ».
  • Commandes User Install : interaction.inGuild() vrai mais interaction.guild souvent null (seul guildId est fourni). Accès direct à interaction.guild.members.
  • Helper resolveInteractionGuild : fetch via client.guilds.fetch(guildId) si interaction.guild absent.
  • /serverinfo et /userinfo utilisent ce helper ; garde-fous sur guild.members / guild.channels.
  • Try/catch sur /userinfo.
  • bot-public/src/lib/resolveInteractionGuild.js
  • bot-public/src/commands/util/serverinfo.js
  • bot-public/src/commands/util/userinfo.js
2026-07-12 20:50 — Lot UX boutique, jeux partagés, profil, support

### 1. Base jeux partagée (sans IGDB)

### 2–4. Fiche produit boutique (garanties + options + prix)

### 5. Accueil — profil Default.xex

### 6. Connexions OAuth (scope + dernière connexion)

### 7. Navbar notifications + mobile

### 8. Boutique mobile — liste

### 9. Ticket partenariat — formulaire dédié

### Impact / déploiement

  • Contexte : même UX « nouveau jeu » (nom + icône) pour ressources, guides et boutique.
  • Changements : table shared_games, API GET/POST /api/shared-games, composant SharedGamePicker (recherche + création).
  • Intégration : formulaires ressources (ajouter), guides (ajouter), boutique (BoutiqueProductForm).
  • Fichiers : web/src/lib/shared-games.ts, web/src/app/api/shared-games/route.ts, web/src/components/shared/SharedGamePicker.tsx, web/src/app/ressources/ajouter/page.tsx, web/src/app/guides/ajouter/page.tsx, web/src/components/boutique/BoutiqueProductForm.tsx
2026-07-12 13:30 — Connexion Discord OAuth prod (invalid_client)

### Contexte

### Cause

### Changements

### Impact

### Fichiers

  • Connexion via Discord impossible sur https://lbxmb.fr (Better Auth invalid_client).
  • PM2 conservait un ancien DISCORD_CLIENT_SECRET (e4DuS8…) qui écrasait la valeur correcte de web/.env.local (oG8LO…).
  • server.js : relecture forcée des clés OAuth depuis .env.local au démarrage.
  • Redémarrage web-prod avec --update-env après sourcing .env.local.
  • OAuth Discord fonctionnel en production (secret client valide côté Discord API).
  • web/server.js
  • docs/RECAP-TRAVAIL-COMMUNAUTE-2026-04.md
2026-07-12 11:08 — Fix démarrage bot-public (import cassé)

### Contexte

### Cause

### Changements

### Fichiers

  • Le bot ne se connectait plus à Discord après les changements forum ressources.
  • Import incorrect dans siteResourceForum.js : ../../lib/logger.js → chemin bot-public/lib/logger.js (inexistant).
  • Correction import → ./logger.js.
  • Redémarrage bot-public : connexion OK (LB'XMB.FR#3591, 4 serveurs).
  • bot-public/src/lib/siteResourceForum.js
  • docs/RECAP-TRAVAIL-COMMUNAUTE-2026-04.md
2026-07-12 10:15 — /blacklist, commandes custom, forum ressources, OG

### /blacklist (remplace /bl)

### Commandes personnalisées (soft)

### Ressources site → salons forum Discord (bot-site)

### Open Graph ressources

  • Contexte : fusion des sous-commandes /bl add|remove|list en une seule commande avec choix d'action.
  • Changements : nouvelle commande /blacklist avec options action (Ajouter / Retirer / Liste), utilisateur ou identifiant obligatoire pour add/remove, temps et raison pour l'ajout. Suppression de bl.js.
  • Impact : propriétaires du bot utilisent /blacklist (global User Install). Déploiement global mis à jour (14 commandes).
  • Fichiers : bot-public/src/commands/owner/blacklist.js, deploy-commands.js, interactionCreate.js, help.js, invite-bot.js
  • Contexte : bouton « Ajouter (bientôt) » inactif dans /config > Administration.
  • Changements : modal création (nom, message, visibilité public/ephemeral), stockage admin.custom_commands, sync guild des slash custom, exécution dans interactionCreate.
2026-07-10 09:36 — User Install : commandes invisibles sans bot serveur

### Contexte

### Cause

### Changements

### Impact

### Fichiers

  • User Install actif mais bot retiré du serveur : plus de commandes visibles sur mobile.
  • Normal : le bot absent du serveur ≠ app désinstallée du compte.
  • 10 commandes musique (guild-only) polluaient le déploiement global User Install.
  • Réinstallation User Install souvent nécessaire après retrait du bot.
  • Global réduit à 14 commandes User Install (translate, help, install, etc.) ; musique déplacée en GUILD_ONLY_COMMAND_NAMES (sync par serveur).
  • Nouvelle commande /install : panneau réinstallation compte + lien DM bot + aide mobile.
  • Doc USER_INSTALL.md mise à jour (DM, Apps, bot hors serveur OK).
  • Liste User Install plus claire sur mobile.
  • Lien DM : https://discord.com/users/1431308308505039069
2026-07-10 09:15 — Fix commandes User Install / invite 0 permission

### Contexte

### Cause

### Changements

### Impact

### Fichiers

  • Après User Install + invitation serveur 0 permission : commandes peu visibles sur mobile, traduction/signalement/blacklist inaccessibles ou cassés.
  • User Install ≠ bot sur serveur : deux installations distinctes.
  • Mobile : commandes dans onglet Applications, pas « Bots du serveur ».
  • Bot serveur 0 permission : ne peut pas lire les messages → /translate et menus contextuels inopérants.
  • /bl et /signalement réservés aux propriétaires du bot.
  • deploy-commands.js : déploiement global toujours (plus de remplacement si DISCORD_GUILD_ID).
  • invite-bot : lien serveur recommandé (permissions minimales) + aide mobile + avertissement 0 perm.
  • botInvite.js : buildGuildInviteRecommendedUrl() (voir salon, lire, répondre).
2026-07-10 09:05 — Commande `/invite-bot` (lien sans permission)

### Contexte

### Changements

### Impact

### Fichiers

  • Demande d’une commande communautaire fournissant le lien d’invitation du bot avec 0 permission (pas admin), en User Install, avec container propre.
  • /invite-bot : commande globale User Install + Guild Install ; panneau Container V2 (avatar, lien, boutons Link).
  • Lien serveur : permissions=0, scope bot + applications.commands.
  • Bouton secondaire User Install (applications.commands seul).
  • lib/botInvite.js : helpers URL ; print-install-links.js : lien 0 permission documenté.
  • N’importe qui peut récupérer le lien d’invitation minimal du bot via /invite-bot (DM, serveur, app installée).
  • bot-public/src/commands/util/invite-bot.js
  • bot-public/src/lib/botInvite.js
  • bot-public/src/lib/{commandSync.js,moderation/guard.js}
2026-07-10 08:52 — Fix `/rpc` Appliquer (UI + pont HTTPS)

### Contexte

### Changements

### Impact

### Fichiers

  • Clic « Appliquer » : config sauvegardée en file mais panneau ne se mettait pas à jour (utilisateur voit « rien »).
  • OAuth seul ne pousse pas la présence sur le profil sans pont RPC local.
  • rpc.js : interaction.update() à la place de deferUpdate + editReply (Containers V2) ; modales mettent à jour le panneau existant.
  • Message explicite après Appliquer avec commande pont PC + secret.
  • userRpc.js : bridge_secret par utilisateur.
  • web/src/app/api/rpc/bridge/route.ts : API HTTPS GET/POST pour le script pont local.
  • rpc-local-bridge.js : support BOT_BRIDGE_URL + RPC_BRIDGE_SECRET.
  • Timeout 2,5 s sur tentative RPC IPC serveur.
  • Le panneau réagit au clic Appliquer avec instructions claires.
  • L'activité profil Discord nécessite Discord Desktop + script pont sur le PC de l'utilisateur.
2026-07-10 08:40 — Recréation `/rpc` (Rich Presence personnalisée)

### Contexte

### Changements

### Impact

### Fichiers

  • Demande de recréer /rpc après suppression (2026-07-04) pour personnaliser l'activité Discord : nom, description, image, boutons (label + URL).
  • OAuth RPC déjà associé au compte (scopes rpc.activities.write, activities.write, presences.write).
  • /rpc : commande globale User Install + panneau Container V2 (type, texte, image URL, 2 boutons, chrono).
  • Stockage data/user-rpc/<userId>.json + file data/user-rpc-queue/<userId>.json.
  • Handlers urpc:* (boutons, modales, sélecteur type).
  • rpcPresence.js : construction payload SET_ACTIVITY + tentative IPC local (discord-rpc).
  • scripts/rpc-local-bridge.js : pont à lancer sur le PC avec Discord ouvert (poll API interne).
  • API interne : GET /internal/rpc/queue/:userId, POST /internal/rpc/ack/:userId.
2026-07-09 ~06:35 UTC — bot-public : sécurité, i18n vocal, sélecteur rôles

### 1. Messages auto — changement de salon (bouton « Changer »)

### 2. Vocal temporaire — traduction panneau post-création

### 3. Sélecteur de rôles — emojis + >25 options

### 4. Traduction automatique — mentions / URLs / emojis

### 5. Attrape-scam (nouveau)

### 6. Anti-raid — modules basic

### 7. Sélecteur de rôles — images embed

### Déploiement

  • Contexte : erreur ❌ Une erreur est survenue en modifiant le salon d'envoi (arrivée/départ).
  • Cause : cfg:field:chan:<section>:<id> mal parsé (chan pris pour action).
  • Changement : branche dédiée b === "chan" avant le parsing générique des champs.
  • Fichiers : bot-public/src/handlers/config/router.js
  • Contexte : boutons et textes en dur (« Autorisé », modales, reset…).
2026-07-09 ~07:35 UTC — bot-public : correctifs sécurité, anti-URL, UI anti-raid, bot secondaire

### 1. Attrape-scam — activation

### 2. Anti-URL — http/https et domaines

### 3. UI anti-raid unifiée

### 4. Bot secondaire vocal

### 5. Sélecteur de rôles — Modifier

### Déploiement

  • Cause : if (a === "scam") interceptait aussi scam:toggle et scam:delmsg.
  • Changement : route scam:cfg pour la page ; toggle fonctionnel ; actif avec salons configurés même sans anti-raid global.
  • Fichiers : routerSecurity.js, securityConfig.js
  • Changement : listes autorisés + interdits ; option bloquer HTTP ; matching sous-domaines.
  • Fichiers : antiRaidModules.js, antiRaidRuntime.js, panelsSecurity.js, routerSecurity.js, securityModals.js
  • Changement : 3 pages dans Anti-raid (Général / Membres / Admin), boutons Configurer, pagination.
2026-07-09 ~08:40 UTC — bot-public : musique multi-bot, config, info, pickup

### 1. Musique — files indépendantes par bot + radio

### 2. /config — navigation directe

### 3. /pickup — User Install

### 4. /userinfo et /serverinfo

### Déploiement

  • Contexte : deux bots vocaux jouaient la même file ; /radio devait suivre la même logique de délégation.
  • Changements : clé file ${voiceGroup}:${guildId} ; panneau lecteur sans bouton Play ; /play envoie le lecteur dans le chat du salon vocal ; /lecteur pour le réafficher ; playlists YouTube dans /play ; /music supprimée.
  • Fichiers : musicManager.js, musicPanel.js, musicSlashHelpers.js, radioManager.js, radio.js, secondaryBot.js, lecteur.js, commandes musique (play, skip, pause, …), interactionCreate.js, commandSync.js
  • Changement : option section (auto, admin, sécurité, notifications, rôles, pseudos, messages, réactions).
  • Fichiers : commands/owner/config.js
2026-07-09 ~09:00 UTC — bot-public : signalement, lecteur, serverinfo, sélecteur rôles

### 1. /signalement — bouton Ignorer

### 2. /lecteur — aucune musique en cours

### 3. /serverinfo — bot absent du serveur

### 4. Sélecteur de rôles — 2ᵉ configuration

### 5. Sélecteur — mode réactions

### 6. Sélecteur — container vs message simple

### Déploiement

  • Changement : le signalement est supprimé de reports.json au lieu d'être marqué ignoré.
  • Fichiers : reportsStore.js, reportHandler.js
  • Changement : message explicite si rien ne joue ; invite à rejoindre un vocal et utiliser /play morceau:….
  • Fichiers : musicSlashHelpers.js
  • Cause : guild.members.fetch() sur un guild où le bot n'est pas membre.
  • Changement : garde-fous ; infos limitées (nom, ID, icône, badges) + mention si le bot n'est pas installé.
2026-07-09 ~17:00 UTC — User Install : liens OAuth + page bot

### Contexte

### Changements

### Liens

### Fichiers

  • Demande d'un lien d'installation User Install avec permissions maximales pour tester l'app sur le compte utilisateur.
  • Configuration API Discord integration_types_config : User Install (applications.commands), Guild Install (bot + admin).
  • Script bot-public/scripts/print-install-links.js (liens serveur, compte, OAuth étendu).
  • Doc bot-public/docs/USER_INSTALL.md.
  • Page web/src/app/discord/bot : boutons Installer sur mon compte et Install + OAuth ; i18n FR/EN.
  • User Install : integration_type=1&scope=applications.commands
  • OAuth étendu : identify, email, guilds, guilds.members.read, connections, applications.commands
  • bot-public/scripts/print-install-links.js, bot-public/docs/USER_INSTALL.md
  • web/src/app/discord/bot/page.tsx, web/messages/discordBot/fr.json, web/messages/discordBot/en.json
2026-07-09 ~17:15 UTC — OAuth User Install : tous les scopes (27)

### Contexte

### Changements

### Fichiers

  • Demande d'inclure tous les scopes OAuth possibles (guilds.join, gdm.join, rpc, voice, etc.), même partenaires/inutiles.
  • ALL_OAUTH_SCOPES (27 scopes) dans print-install-links.js.
  • Lien User Install étendu et lien serveur « nucléaire » mis à jour.
  • Page /discord/bot + doc USER_INSTALL.md.
  • bot-public/scripts/print-install-links.js, bot-public/docs/USER_INSTALL.md
  • web/src/app/discord/bot/page.tsx, web/messages/discordBot/fr.json, web/messages/discordBot/en.json
2026-07-09 ~17:25 UTC — Fix OAuth User Install « champs invalides »

### Cause

### Correction

### Fichiers

  • integration_type=1 n'accepte que applications.commands (pas identify/guilds/gdm.join dans la même URL).
  • Mélange 27 scopes + User Install → erreur Discord.
  • 2 liens : User Install (étape 1) + OAuth compte sans integration_type (étape 2).
  • bot-public/scripts/print-install-links.js, bot-public/docs/USER_INSTALL.md
  • web/src/app/discord/bot/page.tsx, web/messages/discordBot/fr.json, web/messages/discordBot/en.json
2026-07-09 ~17:35 UTC — User Install : un seul lien (max app non approuvée)

### Lien unique

https://discord.com/oauth2/authorize?client_id=1431308308505039069&integration_type=1&scope=applications.commands

### Fichiers

  • bot-public/scripts/print-install-links.js, bot-public/docs/USER_INSTALL.md
  • web/src/app/discord/bot/page.tsx, web/messages/discordBot/fr.json, web/messages/discordBot/en.json
2026-07-07 ~09:15 UTC — Correctifs dev.lbxmb.fr (8 points)

### 1. Bot — changement de salon messages auto (bienvenue)

### 2. SwipePicker — boucle langue / pays

### 3–5. Navbar mobile (dev)

### 6. Connexion Discord sur dev

### 7. Photos fondateurs accueil

### 8. Staff mobile — recherche utilisateur

### Déploiement

  • Contexte : erreur lors du changement de salon sur une config (ex. welcome_dm).
  • Cause : customId découpé par : → section welcome_dm lue comme welcome + id dm.
  • Changement : parsing cfg:chan:set / cfg:add:chan avec slice + join(":") pour les clés de section.
  • Fichiers : bot-public/src/handlers/config/router.js
  • Contexte : après la dernière option, plus de défilement (Fr → En → Es puis stop).
  • Changement : loop: true Swiper + realIndex pour langues et pays dans les paramètres profil.
  • Fichiers : dev-web/src/components/ui/SwipePicker.tsx
2026-07-04 20:22 — Port Minecraft Bedrock 19132 (LBCS'Craft)

### Contexte

### Changements

### Impact visible

### Fichiers touchés

  • Connexion Bedrock impossible : port 19132/UDP non exposé (UFW + aucune allocation Pterodactyl).
  • Plugin Geyser-Spigot configuré sur le port 25565 et incompatible avec Paper 26.2 (crash au démarrage).
  • UFW : ouverture 19132/udp, 25565/tcp+udp, 25575/tcp+udp (Minecraft).
  • Pterodactyl : allocation 19132 testée puis retirée du conteneur MC (Geyser standalone sur l'hôte).
  • Geyser standalone : conteneur Docker geyser-bedrock (/opt/geyser-standalone/), écoute UDP 19132, pont vers Java 151.240.100.62:25565, auth floodgate.
  • Config Geyser plugin (serveur MC) : port Bedrock passé à 19132 (plugin toujours inactif tant que Paper 26.2 incompatible).
  • Bedrock : 151.240.100.62:19132
  • Java : 151.240.100.62:25565
  • data/firewall_config.json
2026-07-04 10:30 — Config auto, stats serveur, sélecteur rôles, retrait /rpc

### 1. Suppression /rpc

### 2. Notifications hors « Système automatique »

### 3. Statistiques serveur (nouveau module)

### 4. Fix sélecteur de rôles (6+ options)

### Déploiement

  • Contexte : commande user-installed peu concluante.
  • Changements : suppression rpc.js, userRpc.js, handlers interaction, entrée commandSync, aide /help.
  • Impact : la commande disparaît après redeploy (18 commandes globales).
  • Fichiers : commands/util/rpc.js (suppr.), lib/userRpc.js (suppr.), interactionCreate.js, commandSync.js, help.js
  • Contexte : doublon avec la page dédiée via la nav /config.
  • Changements : retrait de l'entrée Notifications du hub Système automatique (nav principale inchangée).
  • Fichiers : panelsV2.js
  • Contexte : afficher membres, bots, rôle… dans nom salon / sujet / nom serveur / surnom bot.
2026-07-03 22:40 — Placeholders invite / bot.add

### Changements

### Fichiers touchés

  • {bot.add.mention} et {bot.add.name} (nom d'affichage de l'ajouteur).
  • Retrait de {invite.link} de l'aide ; seul {invite.code} documenté.
  • {invite.display} = nom d'affichage de l'inviteur sur le serveur (plus le nom du salon).
  • {invite.display.name} conservé en alias rétrocompat.
  • Inviteurs bots ignorés pour {invite.display} / compteur.
  • bot-public/src/lib/placeholders.js
  • bot-public/src/handlers/invites/inviteTracker.js
  • bot-public/src/events/guild/guildMemberAdd.js
  • bot-public/src/handlers/welcome/welcomeSender.js
2026-07-03 22:15 — Config : placeholders, bots, vocaux temporaires

### 1. Placeholders vocaux cross-serveur

### 2. Bienvenue / départ — bots

### 3. Rôles auto permanent/temporaire — cible bots

### 4. Vocal temporaire — rôle alerté

### 5. Vocal temporaire — rôles autorisés/interdits

### 6. Aide variables {} contextuelle

### Fichiers touchés

### Déploiement

  • Préférences propriétaire vocal scopées par {guildId}/{userId} (plus de nom figé d'un autre serveur).
  • {display.name}, {username.server}, {user.id} appliqués depuis le template du serveur courant.
  • Cible par entrée : utilisateurs / bots / tous (/config → bouton Changer).
  • Placeholders {bot.mention}, {bot.name}, {bot.id}, {bot.add} (audit log).
  • Champ target sur les règles + filtre dans autoRoleEngine.
  • alert_role_id configurable par config (remplace le rôle hardcodé LB'XMB).
2026-07-03 07:20 — Radio : URLs corrigées + changement sans déco vocal

### Contexte

### Changements

### Fichiers touchés

### Déploiement

  • NRJ, Nostalgie, Fun Radio, Virgin ne fonctionnaient pas (URLs obsolètes 404).
  • Changer de station faisait quitter/rejoindre le vocal (visible sur Play/Xbox).
  • URLs mises à jour après tests ffmpeg (nrjaudio, infomaniak, icecast, bfmtv…).
  • switchStation() : change le flux ffmpeg sans connection.destroy().
  • Réutilisation de getVoiceConnection() si déjà dans le même salon.
  • User-Agent ffmpeg pour les diffuseurs exigeants.
  • bot-public/src/lib/music/radioStations.js
  • bot-public/src/lib/music/radioManager.js
  • bot-public/src/commands/util/radio.js
  • pm2 restart bot-public --update-env
2026-07-03 07:10 — Volume vocal par défaut à 25 %

### Contexte

### Changements

### Fichiers touchés

### Déploiement

  • Le bot arrivait en vocal à 100 % de volume, trop fort pour les utilisateurs.
  • DEFAULT_VOLUME = 0.25 (25 %) appliqué à la musique et à la radio à la connexion vocale.
  • Affichages panneau /music et /queue alignés sur cette valeur par défaut.
  • bot-public/src/lib/music/musicManager.js
  • bot-public/src/lib/music/radioManager.js
  • bot-public/src/lib/music/musicSlashHelpers.js
  • bot-public/src/commands/util/music.js
  • pm2 restart bot-public --update-env
2026-07-03 07:05 — `/radio` visible + commandes musique slash

### Contexte

### Changements

### Impact

### Fichiers touchés

### Déploiement

  • /radio invisible : absente de GLOBAL_COMMAND_NAMES (non déployée globalement).
  • Demande : station en liste déroulante (NRJ, Skyrock…) + commandes /play, /skip, /queue, etc.
  • /radio station: avec choix fixes (12 stations + « Arrêter la radio »).
  • Ajout à GLOBAL_COMMAND_NAMES : radio, play, skip, queue, pause, resume, stop, volume, playlist.
  • Nouvelles commandes musique :
  • /play morceau: — lance ou remplace le morceau en cours
  • /skip, /pause, /resume, /stop
  • /queue — file d'attente
  • /volume niveau: — 0–200 % (sans option = affiche le volume actuel)
  • /playlist ajouter lien: — playlist YouTube (max 50 morceaux)
  • /playlist file — voir la file
2026-07-03 07:05 — `/radio` visible + commandes musique slash

### Contexte

### Changements

### Impact

### Fichiers touchés

### Déploiement

  • /radio invisible : absente de GLOBAL_COMMAND_NAMES (non déployée globalement).
  • Demande : station en liste déroulante (NRJ, Skyrock…) + commandes /play, /skip, /queue, etc.
  • /radio station: avec choix fixes (12 stations + « Arrêter la radio »).
  • Ajout à GLOBAL_COMMAND_NAMES : radio, play, skip, queue, pause, resume, stop, volume, playlist.
  • Nouvelles commandes musique :
  • /play morceau: — lance ou remplace le morceau en cours
  • /skip, /pause, /resume, /stop
  • /queue — file d'attente
  • /volume niveau: — 0–200 % (sans option = affiche le volume actuel)
  • /playlist ajouter lien: — playlist YouTube (max 50 morceaux)
  • /playlist file — voir la file
2026-07-03 06:30 — Bot : rôles temporaires, bienvenue, blacklist, radio

### 1. Rôles temporaires — durées flexibles

#### Contexte

#### Changements

#### Impact

#### Fichiers touchés

### 2. Messages de bienvenue — variables invite

#### Contexte

#### Changements

#### Fichiers touchés

### 3. Blacklist — ban serveurs + MP détaillé

#### Contexte

#### Changements

#### Fichiers touchés

### 4. Commande /radio

#### Changements

#### Fichiers touchés

#### Déploiement

  • La config n'acceptait que des minutes entières.
  • Parser partagé durationParse.js : 30s, 15m, 2h, 7j, 2sem, 1mo, 1an (nombre seul = minutes).
2026-07-02 20:10 — API HTTP interne bot-public (port 25591)

### Contexte

### Changements

### Impact

### Fichiers touchés

### Déploiement

  • Question : le bot utilise-t-il un port ? Les options bot ne marcheraient pas sans.
  • bot-public (Discord /config, modération, etc.) : jusqu'ici aucun port HTTP — uniquement WebSocket Discord + file commands.json.
  • bot-site (sync pseudo/rôles site ↔ Discord) : déjà actif sur 8787 (/health OK).
  • Nouveau serveur HTTP local bot-public/src/lib/internalHttpServer.js sur 127.0.0.1:25591.
  • Routes : GET /health (public), GET /status + POST /internal/flush-verification (header x-api-key = BOT_INTERNAL_SECRET).
  • flushWebVerificationQueue() exporté pour traiter la vérif web sans attendre le poll 5 s.
  • Variables .env : BOT_PUBLIC_HTTP_PORT, BOT_PUBLIC_HTTP_HOST, BOT_INTERNAL_SECRET, LIBRETRANSLATE_URL.
  • ecosystem.config.js : entrées bot-public et bot-site documentées.
2026-07-02 19:45 — Lot UI / bot / IP / boutique (11 demandes)

### 1. IP vérification — parsing headers renforcé

#### Contexte

#### Changements

#### Impact

#### Fichiers touchés

### 2. Blacklist → ban tous les serveurs du bot

#### Changements

#### Fichiers touchés

### 3. Nouveau logo lbxmb.png

#### Changements

### 4. dev.lbxmb.fr redirect prod

#### Cause

#### Changement

#### Fichiers touchés

### 5. Navbar transparente en haut

#### Changement

#### Fichiers touchés

### 6. Domaines : footer, retrait navbar

#### Changements

#### Fichiers touchés

### 7. Menus Applications / mobile

2026-07-02 07:10 — bot-site sync pseudo, majuscules pseudo, `/stats` + config vocal

### 1. bot-site — pseudo + drapeau pays → Discord

#### Changements

#### Fichiers touchés

### 2. Site — majuscules dans le pseudo

#### Changements

#### Fichiers touchés

### 3. bot-public — /stats (ex-/voctime) + /config

#### Changements

#### Fichiers touchés

#### Déploiement

  • Route POST /sync-profile : construit le nick 🇫🇷 Pseudo (max 32 car.) et appelle l'API Discord.
  • Client web discord-bot-site.ts : appelle bot-site au lieu de commands.json (orphelin).
  • Branchement sur changement profil (/api/profil), OAuth (auth.ts, auth-helpers.ts).
  • Variables BOT_SITE_URL + INTERNAL_API_KEY dans web/.env.local.
2026-07-02 — Commandes publiques configurables, /transcript, canvas /stats

### 1. bot-public — commandes publiques gérables dans /config

#### Contexte

#### Changements

#### Fichiers touchés

### 2. bot-public — refonte /transcript

#### Changements

#### Fichiers touchés

### 3. bot-public — redesign canvas /stats

#### Changements

#### Fichiers touchés

#### Déploiement

  • transcript, pickup, base64 étaient déployées globalement → absentes de la sync par serveur : impossible de les désactiver ou de leur assigner des rôles (ex. sondage).
  • GLOBAL_COMMAND_NAMES réduit à : translate, help, music, rpc, signaler.
  • transcript, pickup, base64, sondage, stats passent par la sync par serveur (syncGuildCommands).
  • Permissions publiques sans restriction custom → default_member_permissions: null.
2026-07-02 — Canvas /stats enrichi, page Notifications /config, fix IP nginx

### 1. bot-public — canvas /stats (messages 24h/7j/28j + histogramme)

#### Contexte

#### Changements

#### Fichiers touchés

### 2. bot-public — /config > Notifications

#### Contexte

#### Changements

#### Fichiers touchés

### 3. web + nginx — IP client réelle (plus de 127.0.0.1 partout)

#### Contexte

#### Changements

#### Fichiers touchés

#### Déploiement

### 4. web + nginx + Anubis — fix IP réelle (v2, cause Anubis)

#### Contexte

#### Changements

#### Fichiers touchés

#### Déploiement

2026-07-01 20:15 — UI web : panier, messagerie/tickets, boutique

### 1. Panier hors navbar → menu utilisateur

#### Contexte / problème

#### Changements appliqués

#### Fichiers touchés

### 2. Messagerie tickets — actions + réponse après prise en charge

#### Contexte / problème

#### Changements appliqués

#### Fichiers touchés

### 3. Page panier — contenu sous la navbar

#### Changements

#### Fichiers touchés

### 4. Boutique — icône carrée (pas bandeau)

#### Changements

#### Fichiers touchés

#### Déploiement

  • Le panier ne doit pas apparaître dans la barre de navigation principale.
  • Entrée Mon panier conservée dans le menu profil (desktop dropdown + ProfileMenuSheet mobile).
2026-07-01 19:35 — Vocal temporaire : interdiction utilisateurs + `/voctime` menu + `/to` timeout

### 1. Autorisation vocal temporaire — interdire / réautoriser

#### Contexte / problème

#### Changements appliqués

#### Impact visible / technique

#### Fichiers touchés

### 2. /voctime — parité bot Python

#### Contexte / problème

#### Changements appliqués

#### Impact visible / technique

#### Fichiers touchés

### 3. /to et /unto — timeout Discord (sans salon)

#### Contexte / problème

#### Changements appliqués

#### Impact visible / technique

#### Fichiers touchés

2026-07-01 19:30 — Restauration `deploy.sh` + script `bun run deploy`

### Contexte / problème

### Changements appliqués

### Impact visible / technique

### Fichiers touchés

  • bun run deploy ne fonctionnait plus : script npm deploy absent ; deploy:prod pointait vers /root/lbxmb.fr/deploy.sh supprimé.
  • Recréation de deploy.sh (build → swap .next-staging → pm2 restart web-prod --update-env).
  • Ajout de "deploy": "bash ../deploy.sh" dans web/package.json.
  • Depuis web/ : bun run deploy ou bun run deploy:prod refonctionnent pour la prod.
  • deploy.sh
  • web/package.json
2026-07-01 18:45 — Vérif Discord OAuth, boutique desktop, login ptb/dev, menu profil, recherche messagerie

### Contexte / problème

1. Vérification bot : redirect_uri OAuth2 non valide (URI /api/verify/discord/callback non enregistrée sur le portail Discord ; la bonne URI est /api/verify/oauth/callback).

2. Boutique desktop : layout horizontal type Amazon au lieu d’icône carrée au-dessus du titre.

3. Connexion ptb/dev redirige vers prod (Better Auth sans BETTER_AUTH_URL ni origines ptb/dev).

4. Menu utilisateur partiellement masqué par la bottom nav.

5. Messagerie : besoin d’une barre de recherche en haut + bouton nouvelle conversation à droite.

### Changements appliqués

### Impact visible / technique

### Fichiers touchés

  • VERIFY_OAUTH_CALLBACK_PATH → /api/verify/oauth/callback (authorize + callback + .cjs live).
2026-07-01 12:00 — Fix prod `o.map is not a function` (messages/fr.json manquant)

### Contexte / problème

### Changements appliqués

### Impact visible / technique

### Fichiers touchés

  • Production affichait à nouveau « Erreur critique » : o.map is not a function.
  • Cause racine : messages/fr.json et messages/en.json absents de web/ alors que la locale par défaut est fr. loadMessagesForLocale échouait → messages i18n vides → t.raw("reviews") dans Testimonials renvoyait une chaîne (clé manquante) → .map() sur une string.
  • Restauration de messages/fr.json et messages/en.json depuis ptb-web (web + dev).
  • load-messages.ts : si le fichier base messages/<locale>.json est absent, on continue quand même (merge faq/discordBot) au lieu de tout faire échouer.
  • Garde-fous Array.isArray dans Testimonials.tsx et FAQ.tsx.
  • Rebuild + déploiement des 3 env : prod f8UWlF8yGCTbG6Fpw7OJp, ptb et dev également.
2026-07-01 11:00 — Fix `o.map is not a function` + rebuild dev / ptb / prod

### Contexte / problème

### Changements appliqués

### Impact visible / technique

### Fichiers touchés

  • Erreur critique affichée sur le site : o.map is not a function (boundary Next.js).
  • Cause : dans MessageBell et use-app-queries, res.data.permissions était traité comme tableau via .length alors qu'une chaîne CSV ("fondateur,admin") a aussi une .length → appel de .map sur une string.
  • Demande : rebuild et déploiement des 3 environnements (dev, ptb, prod).
  • Parsing permissions sécurisé via permissionsFromUserRecord() dans MessageBell.tsx et useTicketRedirectAuth (use-app-queries.ts).
  • Garde Array.isArray sur res.data.conversations dans fetchVendorConvs.
  • Rebuild + déploiement :
  • prod (web) → BUILD_ID Ky1Jly3LI4UbvM0Lzg2La, pm2 restart web-prod
  • ptb → BUILD_ID H_s_YgDbcjbIeAZw0kE3y, pm2 restart web-ptb
2026-07-01 10:15 — Sync messagerie prod (dev/ptb → lbxmb.fr)

### Contexte / problème

### Changements appliqués

### Impact visible / technique

### Fichiers touchés

  • Après migration dev → prod, le chat n'était pas aligné : version « propre » (liste unifiée, actions ticket, composer corrigé) sur dev/ptb, mais prod servait encore l'ancien build avec onglets Conversations/Tickets.
  • Cause racine : les arbres web et ptb-web avaient divergé ; la prod tournait sur un .next-staging figé sans rebuild des changements messagerie. Les sources web étaient aussi incomplètes (~36 fichiers manquants vs ptb).
  • Port ptb → web : MessageBell.tsx, ComposeTextarea.tsx (liste unifiée Tickets > Vente > Privé, prise en charge / fermer / transférer, composer aligné).
  • API prod alignées : vérif du niveau d'accès de la cible sur transfert ticket ; permission exposée dans /api/admin/support-staff.
  • Remise en état sources web : copie des 36 fichiers manquants depuis ptb + récupération depuis source maps du build prod + stub SiteIntroduction.tsx + globals.css.
2026-07-01 09:30 — Messagerie ptb : actions ticket + fix composer + remise en état des sources

### Contexte / problème

### Changements appliqués

### Impact visible / technique

### Fichiers touchés

  • Demande (sur ptb) : messagerie unifiée (Tickets > Vente > Privé), pouvoir prendre en charge / fermer / transférer un ticket en respectant les règles de rôle (un support ne peut pas recevoir un ticket de modérateur), et corriger l'alignement du composer.
  • Blocage découvert : les sources de ptb-web étaient partiellement vidées (MessageBell.tsx, Header.tsx, permission-roles.ts, etc. absents) → build impossible.
  • Remise en état de ptb-web : script ptb-web/scripts/recover-src-from-maps.cjs qui récupère les fichiers source manquants depuis les source maps de .next-staging (n'écrase jamais l'existant, filtre les artefacts Next). 22 fichiers restaurés (dont MessageBell.tsx, Header.tsx, permission-roles.ts). SiteWelcomeModal.tsx (absent du build) copié depuis web. → arbre de nouveau buildable (next build OK).
2026-07-01 09:15 — UI panier, tickets messagerie, mobile, boutique

### Contexte / problème

### Changements appliqués

### Impact visible / technique

### Fichiers touchés

  • Panier visible dans la navbar au lieu du menu utilisateur.
  • Actions ticket mal placées ; staff ne pouvait pas répondre après prise en charge (currentUserId = user_id Discord au lieu de users.id interne).
  • Page /panier masquée sous le header fixe.
  • Sur mobile en messagerie : navbar haute gênante ; bottom nav doit rester visible.
  • Cards boutique affichaient les images en bannière pleine largeur au lieu d’icônes carrées.
  • Retrait de CartButton du header ; entrée Mon panier dans le menu profil (sheet mobile + dropdown desktop) avec traduction profileMenu.myCart.
  • Actions ticket staff déplacées en haut de la conversation (Prendre en charge / Fermer / Transférer) ; correction currentUserId via u.id (ID interne DB).
  • /panier : padding top pt-24 sm:pt-28 sous le header fixe.
2026-07-01 09:00 — ptb branché sur la base de données de prod

### Contexte / problème

### Changements appliqués

### Impact visible / technique

### Fichiers touchés

  • La base de ptb (lbxmb_ptb) n'était pas la même que la prod ; demande explicite : ptb doit utiliser la même base que la prod.
  • ptb-web/.env.local : DB_USER, DB_PASSWORD, DB_NAME (+ host/port) réalignés sur la prod → DB_NAME=lbxmb, DB_USER=lbxmb.
  • pm2 restart web-ptb --update-env avec les variables DB de prod exportées (pm2/dotenv ne réécrasent pas une variable déjà chargée).
  • ptb lit/écrit désormais la base de production live (lbxmb). Sessions Better Auth partagées avec la prod ; get-session = 200 ; utilisateur résolu dans les logs.
  • ⚠️ Les actions effectuées sur ptb impactent directement les données de production (choix assumé).
  • ptb-web/.env.local
2026-07-01 08:45 — Fix connexion ptb & dev (DISCORD_CLIENT_SECRET périmé)

### Contexte / problème

### Diagnostic

### Changements appliqués

### Impact visible / technique

### Fichiers touchés

  • Impossible de se connecter sur ptb.lbxmb.fr et dev.lbxmb.fr.
  • Log dev : ERROR [Better Auth]: { error: 'invalid_client', status: 401 } lors de l'échange du code Discord.
  • Les 3 sites partagent le même DISCORD_CLIENT_ID (1431308308505039069) donc doivent partager le même DISCORD_CLIENT_SECRET.
  • Empreintes des secrets : prod 931d3ed6 (correct), ptb & dev b66b652d (périmé). Process live ptb : secret vide.
  • Les endpoints sign-in/social généraient pourtant les bons redirect_uri (ptb/dev), tables Better Auth présentes → seul le secret était en cause.
  • ptb-web/.env.local et dev-web/.env.local : DISCORD_CLIENT_SECRET réaligné sur la valeur de prod.
  • pm2 restart web-ptb web-dev --update-env avec le secret exporté dans le shell (dotenv n'écrase pas une variable déjà présente ; en mode cluster pm2 passe l'env par IPC).
2026-07-01 — Config admin, /stats canvas, /sondage public, DM vérification

### 1. bot-public — /config > Commandes & permissions (échec interaction)

#### Contexte

#### Changements

#### Fichiers touchés

### 2. bot-public — /sondage accessible à tous par défaut

#### Changements

#### Fichiers touchés

### 3. bot-public + web — DM vérification + persistance compte/IP

#### Changements

#### Fichiers touchés

### 4. bot-public — refonte /stats (menu + canvas)

#### Changements

#### Fichiers touchés

#### Déploiement

  • DEFAULT_COMMANDS compte 28 entrées ; Discord limite les StringSelectMenu à 25 options → interaction en échec.
  • Pagination des menus commandes (cmdvis) et permissions (permpick) par blocs de 25.
2026-06-30 20:10 — Commande `/sondage` + compte site auto à la vérification

### Contexte / problème

### Changements appliqués

### Impact visible / technique

### Fichiers touchés

  • Besoin d'une commande /sondage avec un panneau de configuration éphémère (question, description, choix, boutons de vote).
  • En production : tout utilisateur qui se vérifie sur un serveur doit automatiquement obtenir un compte sur le site.
  • Nouvelle commande guild /sondage : ouvre un container éphémère (Components V2) pour construire le sondage.
  • Boutons : « Question / description » (modal), « Ajouter un choix » (modal label + emoji, max 10), bascule mode unique/multiple, « Publier ».
  • Menu déroulant pour retirer un choix.
  • Publication : message public avec barre de progression %, compteur de votes, un bouton par choix + bouton « Clôturer » (auteur ou modérateur ManageMessages).
  • Vote par bouton : bascule du vote, gestion unique vs multiple, mise à jour en direct.
2026-06-30 09:20 — /bot épuré, icône serveur, perms salon (vocaux), vérif conserve l'IP

### Contexte / problème

1. /bot : containers trop chargés (trop de boutons).

2. /bot → page serveur : l'icône du serveur ne s'affiche pas.

3. Présence & statuts : remplacer les multiples boutons par un design épuré.

4. Permissions commande par salon : autoriser les salons vocaux + « échec de l'interaction » après le choix du salon.

5. Vérification : conserver l'IP (très important) + tout l'historique ; si l'utilisateur quitte puis re-vérifie avec une IP différente, garder l'ancienne et ajouter la nouvelle.

### Changements appliqués

### Impact

### Fichiers touchés

  • Point 4 (bug interaction) : dans config/router.js, le channel-select admin (cfg:admin:permchannels:…) était intercepté par le handler générique handleChannelSelect (qui ne l'acquittait jamais) → « échec de l'interaction ». Dispatch déplacé avant le handler générique ; ancien test mort supprimé. Les salons vocaux étaient déjà autorisés (ChannelType.GuildVoice dans le select) et le guard utilise interaction.channelId (fonctionne pour les vocaux).
2026-06-29 23:20 — Confirmation : UDP vers serveurs voix Discord jeté en amont (hébergeur)

### Contexte / problème

### Investigation (preuves définitives)

### Conclusion

### Fichiers touchés

  • Question : « tu as accès à la machine, tu peux activer l'UDP pour le port ? »
  • Firewall local : OUTPUT = ACCEPT, UDP NEW accepté, retours conntrack RELATED/ESTABLISHED autorisés → rien à activer localement, c'est déjà ouvert.
  • STUN Google (UDP port haut 19302) : 10/10 OK → l'UDP haut-port sortant/retour fonctionne en général.
  • Sonde maison : envoi de 15 vrais paquets de découverte d'IP Discord vers le serveur voix live (104.29.144.78:19301, ssrc réel) → 0 réponse. Idem sur plusieurs sessions (104.29.151.x, 104.29.144.x).
  • Ping ICMP vers l'IP voix → Time to live exceeded (boucle de routage) ; TCP/443 vers ces IP → OK ; traceroute UDP s'arrête au hop 5 (37.49.238.59, transit hébergeur).
2026-06-29 23:10 — Diagnostic vocal : cause racine = UDP bloqué par l'hébergeur

### Contexte / problème

### Investigation (preuves)

### Conclusion

### Changements appliqués

### Impact

### Fichiers touchés

  • Le bot rejoint le vocal, trouve le morceau, puis quitte immédiatement ("je viens de lancer mon morceau et le bot à quitter le vocal").
  • generateDependencyReport() : toutes les deps vocales présentes (sodium-native 5.1.0, @discordjs/opus 0.10.0, ffmpeg, DAVE). → pas un souci de lib.
  • Repro via script de diag (bot rejoint un vocal vide et joue) : la connexion reste bloquée en connecting puis timeout 20 s → destroy(connect-failed).
  • Debug @discordjs/voice (debug: true) : le WebSocket vocal fonctionne (op 2 reçu avec ip/port du serveur média Discord, modes aead_aes256_gcm_rtpsize/aead_xchacha20_poly1305_rtpsize). Le blocage est à l'étape suivante : la découverte d'IP UDP n'aboutit jamais.
2026-06-29 23:00 — Fix vocal réel (sodium-native) + redirect_uri callback

### Contexte / problème

### Changements appliqués

1. redirect_uri du callback (prod)

2. Audio vocal — libsodium-wrappers cassé sous ESM

### Impact

### Fichiers touchés

  • Vérif : échange du code Discord refusé (Invalid "redirect_uri" in request).
  • Musique : le bot reconnaît le morceau mais ne joue rien en vocal (connexion OK, son absent).
  • Le build figé d'authorize utilise /api/verify/oauth/callback, alors que le .cjs envoyait en dur /api/verify/discord/callback → mismatch.
  • verify-oauth-callback.cjs réutilise désormais le chemin entrant réel (= le redirect_uri validé par Discord). Testé live : les deux chemins renvoient « Invalid code » (et non plus « Invalid redirect_uri ») → le redirect_uri correspond, un vrai code aboutit.
  • Diagnostic : sous ESM, après await ready, libsodium-wrappers n'expose ses méthodes que sur .default, pas sur le namespace ; or @discordjs/voice appelle lib.crypto_aead_xchacha20poly1305_ietf_encrypt sur le namespace → undefined → chiffrement des paquets vocaux échoue → connexion « Ready » mais silence.
2026-06-29 22:45 — Fix vocal (chiffrement), refonte container /music, fix « serveur introuvable »

### Contexte / problème

### Changements appliqués

1. Fix vocal — bibliothèque de chiffrement manquante

2. Refonte container /music

3. Fix vérif « serveur introuvable »

### Impact

### Fichiers touchés

  • Musique : « ❌ Connexion au salon vocal impossible » — le bot rejoignait le vocal mais ne jouait rien et repartait.
  • /music devait envoyer directement un container (pas de choix obligatoire) avec menu déroulant des morceaux + boutons complets.
  • Vérification web : « serveur introuvable » lors de la vérif.
  • @discordjs/voice@0.19.2 exige une lib de chiffrement (modes AEAD imposés par Discord) ; aucune n'était installée → la connexion ne passait jamais Ready → déconnexion immédiate.
2026-06-29 22:10 — /music (container + boutons), streaming yt-dlp, fix vérif OAuth

### Contexte / problème

### Changements appliqués

1. Streaming musique → yt-dlp + ffmpeg (approche fiable 2026)

2. /music = commande unique + container

3. Fix vérif « échange du code Discord refusé »

### Impact

### Fichiers touchés

  • /music était une commande à sous-commandes (play/skip/stop/...) ; demande : une seule commande avec un container et les actions en boutons.
  • Lecture cassée : le bot rejoignait le vocal, trouvait le morceau, puis quittait immédiatement. Cause : play-dl@1.9.7 ne parvient plus à streamer YouTube (lib obsolète, flux vide → player Idle).
  • Vérification web : erreur récurrente « échange du code Discord refusé ».
  • Installé le binaire yt-dlp (/usr/local/bin/yt-dlp, v2026.06.09). Testé OK depuis le serveur (recherche + extraction flux).
2026-06-29 17:05 — Inter-salon (réactions/épingles), fix config messages, commandes /bl /bot /signaler, panier boutique

### 1. Fix : messages de bienvenue/départ « échec de l'interaction » au clic « Configurer »

Impossible de configurer les sections de messages automatiques (bienvenue, départ, etc.) : le clic sur « Configurer » renvoyait « échec de l'interaction ».

Collision de préfixe de customId. Les sections de messages auto utilisaient cfg:sec:open:<section> (« sec » = section) alors que le module Sécurité capte tout parts[1] === "sec" (isSecurityButton). Le bouton était donc routé vers la sécurité, qui ne connaît pas l'action open → aucune réponse → interaction échouée.

### 2. Inter-salon : synchronisation réactions (ajout), épingles, sondages

### 3. Commande /bl — blacklist globale (réservée aux propriétaires)

### 4. /statut → /bot (gestion complète du bot)

### 5. Commande /signaler — signalement d'utilisateur (guild + user install)

2026-06-29 09:30 — Fix critique messageCreate + erreur modale invitation

### 1. Import manquant cassant TOUS les handlers de messages

Le bot ne relayait aucun message inter-salon, et plus largement l'anti-spam / threads / réactions / traduction ne se déclenchaient pas.

messageCreate.js appelait tryPendingBotImport(message) sans l'importer → ReferenceError à chaque message → tout le code suivant (handleAutoReactions, handleAntiSpamMessage, handleCrossChannelMessage, traduction, threads) ne s'exécutait jamais (rejet silencieux capté par unhandledRejection).

### 2. Modale d'invitation : erreur visible bien que l'action réussisse

La soumission de la modale faisait interaction.update() puis interaction.followUp() systématiquement → l'enchaînement provoquait une erreur côté client alors que l'invitation était bien enregistrée.

  • Ajout de l'import tryPendingBotImport depuis lib/botProfileImport.js.
  • Le relais inter-salon, l'anti-spam et les autres traitements de messages fonctionnent à nouveau (redémarrage du bot requis).
  • bot-public/src/events/message/messageCreate.js
2026-06-29 09:15 — OAuth verify (redirect_uri), bouton info, inter-salon par invitation

### 1. Vérification web : « échange du code Discord refusé »

Après connexion Discord, retour sur le site en erreur « échange du code Discord refusé ».

### 2. Bouton « En savoir plus » en bleu + non-accès admin aux IP

### 3. Connexion inter-salon : modèle par serveur + invitations

Les configs inter-salon devaient être individuelles (aucun serveur ne modifie la config d'un autre) avec un système d'invitation : on invite un serveur par ID, il accepte et choisit son propre salon.

  • Paire client_id/client_secret validée OK (grant client_credentials → 200) : ce n'est pas un invalid_client.
  • Cause : la route /api/verify/oauth/callback appelait handleVerifyOAuthCallback(request, {}) → redirect_uri du token calculé avec le chemin par défaut (/api/verify/discord/callback), différent du chemin réellement appelé → invalid_grant.
  • verify-oauth-callback-logic.ts : le redirect_uri du token est désormais reconstruit depuis le chemin réel de la requête entrante (new URL(request.url).pathname) → correspond toujours à celui utilisé à l'autorisation, quelle que soit la route de callback.
2026-06-29 08:50 — Vérif (refonte), publier intelligent, anti-spam, connexion inter-salon

### 1. Container de vérification refait

Le panneau de vérification manquait de clarté sur l'intérêt de la vérification et les données récoltées.

### 2. « Publier panneau » : nouveau container si le salon a changé

Republier le panneau de vérif après avoir changé de salon laissait l'ancien panneau orphelin dans l'ancien salon.

### 3. Anti-spam corrigé

L'anti-spam ne se déclenchait pas (spam répété sans effet).

### 4. Connexion inter-salon (bridge multi-serveurs)

Synchroniser un même salon (ex. « entraide ») entre plusieurs serveurs où le bot est présent.

  • buildVerificationPanelPayload : nouvel embed « Vérification requise » qui explique qu'il faut se vérifier pour accéder au serveur, avec 2 boutons.
  • Bouton Me vérifier : lien direct vers l'URL de vérification du serveur (lbxmb.fr/verify/<id>) en méthode web ; bouton custom en méthode bouton ; masqué en méthode réaction.
2026-06-29 — 20:55 · Signalements consultables, restrictions par salon, /music, /bot paginé, contestations par bouton, /help

### Contexte / problème

Suite de la session : (1) consulter les signalements sans DM, (2) restreindre l'usage de commandes à certains salons, (3) lecteur musique YouTube en vocal, (4) panneau /bot trop chargé, (5) /contestation était une erreur (un bouton est attendu, pas une commande), (6) commande d'aide listant les commandes publiques et cliquables.

### 1. /signalement — consultation des signalements (propriétaires)

### 2. Restriction des commandes par salon (/config > Autorisations)

### 3. /music — lecture YouTube en vocal

### 4. /bot — panneau séparé en pages

### 5. Contestation par bouton (suppression de /contestation)

### 6. /help — aide paginée et cliquable

### Déploiement

2026-06-29 — 21:10 · Verify (UX), signaler contextuel, couleur de bouton sélecteur, /voctime, /backup container

### Contexte / problème

Retour utilisateur : (1) erreur serveur introuvable à la vérification + besoin d'un message clair quand la vérif est désactivée ; (2) signalement via menu contextuel utilisateur (modale) ; (3) sélecteur de rôles en mode boutons : les boutons n'ont pas de description → choisir une couleur ; (4) réintroduire /voctime (système du bot Python) ; (5) /backup en container avec menu déroulant et boutons contextuels.

### 1. Vérification web

### 2. Menu contextuel « Signaler » (utilisateur)

### 3. Sélecteur de rôles — couleur des boutons

### 4. /voctime (temps vocal)

### 5. /backup — container + boutons contextuels

### Déploiement

### Fichiers touchés

2026-06-28 13:00 — Panels : edit ou renvoi si message supprimé

Lors de la mise à jour d'un container (vérif, vocal temporaire, sélecteurs, /config, /role), le bot tentait un edit sur un message supprimé — échec silencieux, panneau perdu.

  • Nouveau module panelMessage.js : editOrResendChannelMessage (fetch forcé → edit, sinon renvoi + MAJ ID) et safeInteractionUpdate / safeInteractionEditReply (fallback followUp si message d'origine introuvable).
  • Appliqué à : vérif, vocal temporaire, sélecteurs rôles/pseudo, /role, tous les routeurs /config.
  • Suppression manuelle d'un panneau → resync le recrée automatiquement.
  • Interaction sur un message supprimé → nouveau message éphémère au lieu d'une erreur muette.
  • bot-public/src/lib/panelMessage.js
  • bot-public/src/handlers/{verification/verificationPanel.js,tempVoice/controlPanel.js,roles/roleSelector.js,nicks/nickSelector.js,role/roleCommandHandler.js,config/{router.js,routerSecurity.js,routerRoles.js,routerNicks.js,routerCommunity.js,routerReactions.js,routerAdmin.js,editFlowV2.js,securityModals.js}}
  • docs/RECAP-TRAVAIL-COMMUNAUTE-2026-04.md
2026-06-26 08:15 — Template vocal {display.name}, sélecteur rôles

1. Template vocal {display.name} affiché littéralement au lieu du nom d'affichage.

2. Sélecteur de rôles : pas de personnalisation nom/description/emoji par option ; multi-sélection peu claire.

  • Vocal temporaire : templateName() utilise applyPlaceholders() ({display.name}, {username.server}, {user}, etc.).
  • Sélecteur rôles : flux option = choisir rôle → modale nom/description/emoji ; description publiée dans le menu ; type par défaut select (multi-rôles cochables) ; suppression d'option.
  • bot-public/src/{handlers/tempVoice/tempVoiceHandler.js,handlers/config/{panelsRoles.js,routerRoles.js,roleModals.js,routerCommunity.js,panelsCommunity.js},handlers/roles/roleSelector.js,lib/roleConfig.js}
  • docs/RECAP-TRAVAIL-COMMUNAUTE-2026-04.md
2026-06-26 07:45 — Vocaux auth toggle, placeholders, locale auto

1. Autorisations vocaux : menu utilisateurs avec cocher/décocher.

2. Placeholders bienvenue : {username.server}, {id.user}, {web.user} manquants.

3. Menu langue panneau vocal inutile — locale client puis serveur.

  • Auth vocaux : un UserSelectMenu multi (min 0) avec utilisateurs pré-cochés ; décocher retire l'accès.
  • Placeholders : {username.server}, {id.user}, {web.user} dans placeholders.js.
  • Locale : plus de select langue ; panneau = langue serveur ; éphémères = langue client → fallback serveur.
  • bot-public/src/{handlers/tempVoice/controlPanel.js,lib/placeholders.js,lib/discordLocale.js}
  • docs/RECAP-TRAVAIL-COMMUNAUTE-2026-04.md
2026-06-26 07:00 — Vocaux Container, DMs sanctions, bio, traduction bouton

1. Panneau vocal : repasser en Container V2 avec toggles permissions ; corriger bouton Autorisation ; sections users/rôles.

2. Commandes mod : pas de MP utilisateur ni contestation.

3. /status : presets bio rotatifs manquants.

4. Traduction auto : select langue fixe au lieu de la locale client.

  • Vocaux temporaires : Container V2 avec toggles Autorisé/Interdit ; fix bouton Autorisation ; panneau éphémère UserSelect/RoleSelect.
  • Modération : MP auto + bouton Contester + /contestation ; stores sanctions/contestations.
  • /status : presets bio + rotation dynamique (applyBotBio).
  • Traduction auto : bouton Traduire (locale client) ; helper translateForInteraction.js.
  • Autorisations vocales fonctionnelles ; utilisateurs sanctionnés informés ; bio rotative ; traduction selon langue client.
  • bot-public/src/{handlers/tempVoice/controlPanel.js,handlers/moderation/contestationHandler.js,handlers/autotranslation/autoTranslationHandler.js,commands/moderation/*,commands/owner/status.js,lib/botStatus.js,lib/moderation/*,events/*}
2026-06-26 06:15 — /record, vocaux embed, /status presets

1. /record : téléchargement MP3 impossible depuis le select ; dates non Paris ; pas de limite 25 avec rotation.

2. Vocaux temporaires : panneau simplifié sans embed permissions/autorisations du bot Python.

3. /status : un seul statut ; pas de rotation dynamique entre presets.

  • /record : fix téléchargement (deferUpdate + followUp avec fichier) ; dates Europe/Paris ; max 25 enregistrements par utilisateur (suppression des plus anciens).
  • Vocaux temporaires : embed complet (permissions @everyone, langue, limite) ; menus permissions/langue ; panneau Autorisation (ajouter/expulser/réinitialiser via MentionableSelect).
  • /status : presets multiples (ajout/suppression/sélection) ; mode dynamique avec intervalle configurable ; rotation au démarrage (startStatusRotation).
  • Téléchargement des enregistrements depuis l’historique ; horodatage Paris (heure d’été incluse).
  • Panneau vocal identique au bot Python (embed + permissions + utilisateurs/rôles autorisés/interdits).
  • Statut du bot rotatif entre plusieurs presets configurés.
2026-06-26 05:36 — Profil éphémère, vocaux temporaires, /record

1. Profil bot : trop de messages publics lors des imports/applications.

2. Demande d’importer le système Vocal temporaire du bot Python dans Système automatique (UI Container).

3. Nouvelle commande /record : rejoindre un vocal, enregistrer en MP3, historique + téléchargement.

  • Profil bot : import fichier → réaction ✅/❌ (plus de reply public) ; Appliquer → deferUpdate silencieux ; messages d’import en éphémère uniquement.
  • Vocaux temporaires : portage join-to-create (tempVoiceHandler.js), config multi-entrées compatible Python, panneau contrôle Container (renommer/limite/supprimer), hub /config → Système automatique.
  • /record : @discordjs/voice + ffmpeg → MP3 VBR ; container Démarrer/Arrêter + select téléchargement ; stockage data/recordings/<userId>/.
  • Configuration profil bot sans spam salon.
  • Vocaux temporaires configurables comme sur le bot Python (sans MySQL).
  • Enregistrement vocal utilisable (ffmpeg requis, déjà présent sur le serveur).
2026-06-26 05:00 — Traduction, profil serveur, threads Python, RPC

1. Traduction auto : « Aucun texte à traduire » (intent Message Content absent + résolution message fragile).

2. Profil bot trop limité vs bot Python (PATCH /guilds/.../members/@me).

3. Question RPC / scope activities.write.

4. Threads auto : config OK mais création de fils inactive.

  • Traduction : intent MessageContent ; cache disque data/translation-cache.json ; résolution via référence du reply (comme Python) ; menu seulement si texte ≥ 3 caractères.
  • Profil bot : guild.members.editMe() (nick, avatar, bannière, bio serveur) ; UI import URL/fichier restaurée.
  • Threads : logique portée depuis imagethread_handler.py (autoThreadMedia.js) ; permissions complètes incl. SendMessagesInThreads + ManageMessages ; logs création.
  • RPC : message explicite sur limite activities.write (bot ≠ OAuth client RPC).
  • Traduction fonctionnelle si Message Content activé dans le portail Discord.
  • Personnalisation bot par serveur comme le bot Python, sans toucher au profil global.
2026-06-25 15:25 — UI gras/emojis, threads autorisés, traduction, profil bot

1. Hub config : remettre emojis à gauche + libellés en gras (pas sur les boutons) ; idem Administration.

2. Threads : remplacer « Exiger » par « Autoriser » (texte seul, URL, médias, légende).

3. Traduction auto : « Aucun texte à traduire » malgré message avec contenu ; pas de drapeaux dans le menu.

4. Profil bot : échec interaction sur Appliquer ; import uniquement par URL.

  • Hub auto + admin : format emoji Nom à gauche, boutons sans emoji.
  • Threads : règles allow_* + formats médias (png, webp, mp3, mp4, mkv, aac/acc, avi, jpeg, jpg, dds) ; migration legacy require_*.
  • Traduction : cache texte à la réception + résolution fiable ; drapeaux sur chaque langue du menu.
  • Profil bot : deferUpdate + followUp pour Appliquer ; boutons Importer fichier (PJ dans un salon, 2 min) + URL conservée.
  • UI cohérente ; threads configurables en mode « autorisé » ; traduction auto fonctionnelle ; import avatar/bannière simplifié.
2026-06-25 15:15 — UI config, /backup unifié, réactions & traduction

1. Page Système auto : emojis doublons, section Communauté regroupait traduction + threads.

2. /backup en sous-commandes au lieu du panneau unique bot Python.

3. Réactions auto : mode salons confus, modale mots en échec.

4. Traduction auto : ajout/retrait salon un par un.

5. Threads : pas de config des emojis de réaction par règle.

  • Hub auto épuré : titre simple, 6 entrées distinctes sans emoji redondant.
  • /backup unifié : panneau Créer / Appliquer / Supprimer + sélecteur + modal SUPPRIMER.
  • Réactions : mode tous salons vs salons choisis ; modales corrigées (update).
  • Traduction : multi-sélection salons (décocher = retirer).
  • Threads : bouton Réactions + modale emojis par config.
  • Navigation /config plus claire ; backup en une commande ; config fiable.
  • bot-public/src/handlers/{config/panelsV2.js,config/panelsCommunity.js,config/panelsReactions.js,config/routerCommunity.js,config/routerReactions.js,config/communityModals.js,backup/backupHandler.js}
2026-06-25 14:55 — Réactions auto, restauration rôles, /status, transcript HTML

1. Besoin de réactions automatiques (mot précis ou tous les messages, style MEE6).

2. Restauration des rôles mélangée aux rôles permanents — à isoler dans le hub rôles.

3. /config ne doit jamais être désactivable.

4. Commande /status réservée à l'utilisateur 1139951514694193323.

5. /transcript limité au TXT du salon courant — export HTML + portée serveur demandés.

  • Réactions automatiques : schéma auto_reactions, handler messageCreate, UI /config > Système auto (salons, mots, tous messages, emojis).
  • Restauration rôles : kind restore dans le hub (à côté permanent/temp/action/sélecteurs) ; retrait du toggle sur les permanents ; migration restore_on_rejoin → règles restore.
  • /config protégée : forcée visible+enabled (cmdvis, guard, withDefaults) ; note UI « toujours active ».
  • /status : commande globale owner-only, panneau présence (online/idle/dnd/invisible), type activité, modales texte/emoji/URL stream ; persistance data/bot-status.json ; appliquée au démarrage.
2026-06-25 14:44 — Backup guild, communauté, clear, visibilité rôles

1. Rôle autorisé pour /config mais commande invisible (default_member_permissions Administrator).

2. /backup = simple export JSON, pas le système Python.

3. Pas de traduction automatique ni threads automatiques dans /config.

4. /clear sans filtre utilisateur.

  • Visibilité slash : sync default_member_permissions depuis les bits des rôles autorisés ; resync après changement autorisations.
  • /backup : snapshot guild v7 (rôles, salons, bans, membres, config bot) ; sous-commandes creer, liste, restaurer, supprimer ; restauration multi-parties.
  • /clear : option utilisateur (filtre auteur, threads supportés).
  • Communauté (/config > Système auto) : traduction auto (menu langues sur messages) + Thread automatique (containers, règles texte/URL/PJ, réactions, plusieurs configs/salon).
  • Schémas autotranslation, auto_threads ; migration legacy imagethread.
  • Modérateurs avec rôle autorisé voient /config si le rôle a les permissions Discord correspondantes ; backup/restauration type bot Python ; nouveaux systèmes communauté configurables.
2026-06-25 09:45 — Fix autorisations, import profil URL, commandes masquées

1. Import avatar/bannière profil bot toujours inopérant (/config éphémère → collecteur de messages inefficace).

2. Commande masquée encore visible dans Discord ; pas de message clair à l'utilisation.

3. Utilisateurs autorisés dans /config > Autorisations ignorés (/config et hasConfiguredAccess hardcodés propriétaire uniquement).

  • Import profil : modale URL (copier le lien Discord) à la place du collecteur de pièces jointes ; saveBotAssetFromUrl.
  • guard.js refondu : source unique admin.permissions ; checkCommandAccess centralisé dans interactionCreate.js.
  • /config + panneau boutons : accès propriétaire ou utilisateurs/rôles listés dans admin.permissions.config.
  • Message explicite si commande masquée : « désactivée sur ce serveur ».
  • Sync commandes : rappel éphémère (cache Discord 1–5 min).
  • Les 2 utilisateurs autorisés sur /config peuvent l'utiliser ; import image fiable ; commandes masquées bloquées à l'exécution avec message clair.
2026-06-25 09:08 — Admin commandes, permissions, import profil, traduction

1. Bouton « Basculer » commandes → échec d'interaction (trop de composants V2).

2. Demande menu multi-sélection visibilité + permissions rôles/utilisateurs par serveur (visibilité Discord).

3. Import avatar/bannière profil bot sans effet (filtre pièce jointe trop strict).

4. Traduction découpée en plusieurs messages + drapeau dans le titre — format rejeté.

  • Commandes : StringSelectMenu multi-sélection (cfg:admin:cmdvis) — cocher les commandes à conserver ; sync guild.commands.set() par serveur via lib/commandSync.js.
  • Permissions : choix commande → RoleSelectMenu + UserSelectMenu ; persistance admin.permissions ; sync permissions Discord par guild.
  • Deploy : commandes modération/config en guild-only ; globales limitées à translate, base64, transcript, pickup + menu contextuel.
  • Profil bot : filtre image élargi (extension si contentType absent) + confirmation éphémère après import.
  • Traduction : un seul message ; footer -# Traduction 🇺🇸 => 🇫🇷 ; fichier .txt si > 2000 caractères.
2026-06-25 07:37 — Fix traduction, /config paginé, base64 Python, import profil bot

1. Traduction : crash interaction.member null sur menu contextuel → message générique.

2. Container /config trop long — demande de pages + menu déroulant en bas.

3. /base64 incomplet vs bot Python (chiffrer/déchiffrer + bouton Déchiffrer).

4. Profil bot : import image avatar/bannière (pas d’URL).

  • guard.js : commandes publiques (translate, base64…), guildId safe, fetch member si absent.
  • /config scindé : Système automatique / Administration + StringSelectMenu navigation.
  • /base64 : choix encode/decode → modales ; réponse avec bouton 🔓 Déchiffrer (b64:decrypt).
  • Profil bot : boutons Importer (pièce jointe 60s) → data/bot-assets/<guild>/.
  • Traduction contextuelle fonctionnelle ; UI config compacte ; base64 identique au bot Python ; avatar/bannière par upload.
  • bot-public/src/lib/moderation/guard.js
2026-06-25 07:25 — Pseudos auto, admin, profil bot, traduction, modération
  • Nouvelles sections /config : pseudos automatiques, administrateur (commandes/permissions), profil du bot.
  • /translate + menu contextuel « Translate this message » via LibreTranslate local (User Install).
  • Recréation des commandes modération de base.
  • Schéma auto_nicks, admin, bot_profile dans serverConfig.js ; placeholder {web-user}.
  • Moteur pseudos (permanent, temporaire, sélecteur V2) + verrouillage manuel (soi / autres).
  • Hub /config : séparateur Administrateur + profil bot (apply avatar/bio/nickname).
  • Admin : liste commandes activables, permissions (squelette), custom commands (squelette).
  • lib/libretranslate.js (port TS) ; /translate + context menu ; /transcript, /pickup User Install.
  • 18 commandes modération : ban, kick, mute, warn, lock, clear, backup, etc.
  • 23 commandes déployées ; PM2 redémarré.
  • Configuration pseudos RP (maisons, formats {display.name}) ; gestion commandes serveur ; modération opérationnelle ; traduction DM/serveurs sans bot.
2026-06-24 21:45 — Conditions statut, jours custom, sélecteur V2 toggle

1. Rôles par action : manque condition sur texte du statut personnalisé.

2. Âge du compte : rôles pour comptes au-delà de X jours, sans presets (saisie libre).

3. Sélecteur publié : description du container configurable ; boutons/menu dans le container V2.

4. Menu déroulant sélecteur : pouvoir retirer un rôle (décocher).

5. UI /config : séparateur avant les boutons Ajouter / Retour en bas de page.

  • Condition custom_status + intent GuildPresences + event presenceUpdate pour réattribuer à la volée.
  • Jours (account_age_days_min/max) via modale (nombre libre) ; libellé « créé il y a plus de X jours ».
  • publishRoleSelector : message Components V2 (ContainerBuilder) avec titre/description/couleur ; édition si message_id existant.
  • StringSelectMenu publié : minValues(0), sync add/remove selon sélection.
  • Helpers addFooterActions dans panelsRoles.js et panelsV2.js (séparateur avant footer).
2026-06-24 21:15 — UX rôles /config : salon, multi-rôles, conditions en menus

1. Choix du salon du sélecteur de rôles sans effet (routing ChannelSelect intercepté par le router messages).

2. Impossible de sélectionner plusieurs rôles d'un coup (permanent, temporaire, sélecteur).

3. Conditions « rôle par action » via modale — demande de menus déroulants.

4. Boutons « Configurer » pas tous bleus ; accueil /config avec liste dupliquée.

  • router.js : délégation cfg:roles:selchanset:* vers handleRolesInteraction.
  • panelsRoles.js : RoleSelectMenu intégré à l'éditeur (maxValues: 25) ; fusion des IDs sélectionnés.
  • Panneaux conditions (buildConditionsPanelPayload / buildConditionValuePanelPayload) avec StringSelectMenu ; presets dans conditions.js.
  • Options sélecteur : choix du rôle via RoleSelectMenu (plus de modale option).
  • Accueil /config simplifié (« Système automatique » + sections + Configurer bleu) ; tous les Configurer en Primary.
2026-06-24 20:40 — /config accueil, modales titre/desc, rôles automatiques
  • /config ouvrait directement « Messages automatique » au lieu de l'accueil fonctionnalités.
  • Titre/description : demande de modales (titre vide autorisé) au lieu du chat.
  • Nouvelle fonctionnalité Rôles automatiques : permanents (restauration au retour), temporaires (durée), par action (badge, âge compte, connexion), sélecteurs (boutons/menu).
  • /config → buildHomeContainerPayload (Messages + Rôles automatiques).
  • Modales textFieldModals.js pour titre (optionnel) et description ; router modal submit.
  • Schéma auto_roles dans config serveur ; roleConfig, roleRestoreStore, tempRoleStore.
  • Moteur autoRoleEngine (join/leave), tempRoleScheduler, conditions, roleSelector (publish + toggle).
  • UI panelsRoles.js + routerRoles.js ; accueil rôles → 4 sections configurables.
  • Connexions OAuth : lecture data/connections/<userId>.json (sync bot-site).
  • Configuration unifiée ; rôles auto à l'arrivée ; panels réaction/boutons/menu publiables.
2026-06-24 19:05 — Fusion /config + /config2, fix erreur 40 composants, UX boutons
  • Fusionner /config et /config2 (Containers V2 uniquement sur /config).
  • Erreur « ❌ Une erreur est survenue » à l'ouverture de l'éditeur / à l'ajout : limite Discord 40 composants dépassée (éditeur monolithique ~48).
  • Renommer « Gérer » → « Modifier » ; bouton Retour toujours seul sur sa ligne.
  • /config utilise désormais Components V2 (auto panel) ; commande /config2 supprimée.
  • Préfixe interactions unifié cfg: ; router V1 embed supprimé, router unique dans router.js.
  • Éditeur scindé en hub + sous-pages (Message / Carte / Régulier) pour rester sous la limite de 40 composants.
  • Helper addBackRow() : Retour/Annuler jamais mélangé aux autres boutons.
  • Déploiement slash commands (1 commande) ; redémarrage PM2.
  • /config fonctionnel sans erreur ; navigation par sous-panneaux ; UX cohérente.
  • bot-public/src/commands/owner/config.js (suppression config2.js)
2026-06-24 16:30 — /role, anti-raid, vérification, page verify

1. /role : afficher la progression membre par membre (Pseudo 22/183).

2. Config sécurité : anti-spam doit être une option dans anti-raid.

3. Vérification : vider les rôles, panneau Discord refait, option compte lbxmb.fr.

4. Page lbxmb.fr/verify/[id] : serveur introuvable, OAuth refusé, pas de nom/logo.

  • /role : progression Pseudo \22/183\`` pendant l’attribution en masse.
  • Anti-raid : hub Config > Sécurité > Anti-raid > Anti-spam (seuil, fenêtres, sanctions dont suppression seule).
  • Vérification Discord : Container V2 (Me vérifier + À savoir éphémère) ; vider rôles ; toggle compte lbxmb.fr.
  • Site verify : config fusionnée bot-public + legacy ; métadonnées Discord API ; handler server.js pour prod sans rebuild ; secret OAuth Discord corrigé (invalid_client).
  • Progression visible sur attributions massives ; hiérarchie anti-raid cohérente.
  • Panneau vérification professionnel avec explication RGPD via « À savoir ».
2026-06-24 15:45 — Vocal temporaire : layout boutons + alerte dans le container

1. Boutons du panneau vocal sur une seule ligne — souhait de 2 lignes (Renommer | Autorisation / Limite | Supprimer).

2. Mention du rôle vocal dans un message séparé — tout doit être dans le container avec « Alerte @vocal » uniquement.

  • Boutons répartis sur 2 lignes dans le Container V2.
  • Ligne Alerte <@&rôle> en tête du container ; suppression du message texte séparé.
  • Ping du rôle 1520182284198744184 uniquement à la création du vocal (pingRole: true).
  • Panneau plus lisible ; une seule message container ; notification ciblée au rôle vocal à l'ouverture.
  • bot-public/src/handlers/tempVoice/{controlPanel.js,tempVoiceHandler.js}
  • docs/RECAP-TRAVAIL-COMMUNAUTE-2026-04.md
2026-06-24 15:15 — Vocal temporaire : ping rôle + historique messages

1. Création d'un vocal : le texte « Permissions @everyone » dans le panneau pingait tout le serveur.

2. Souhait de ping le rôle « cherche du monde vocal » (1520182284198744184) à la place.

3. Permission Historique des messages absente pour @everyone sur les vocaux créés.

  • Libellé panneau : « Permissions du salon » (plus de @everyone dans le texte).
  • À la création : message <@&1520182284198744184> avec allowedMentions ciblé ; panneau sans mentions parsées.
  • Overwrites @everyone à la création : inclut ReadMessageHistory (+ messages, pièces jointes, commandes).
  • Toggle Historique des messages ajouté au panneau de permissions.
  • Plus de ping @everyone à la création ; seuls les membres avec le rôle vocal sont notifiés.
  • Chat du vocal : historique des messages lisible pour tout le monde.
  • bot-public/src/handlers/tempVoice/{controlPanel.js,tempVoiceHandler.js}
2026-06-24 14:30 — /role, config Sécurité, anti-spam, vérification

1. Commande /role éphémère pour attribuer/retirer des rôles en masse (membres ou tout le serveur).

2. Page /config Sécurité & protection : anti-spam (anti-raid) + vérification (portage bot Python).

  • /role : container éphémère V2 (UserSelect, RoleSelect, « Tous les membres », Ajouter/Retirer, Appliquer) ; respect hiérarchie des rôles.
  • Config Sécurité : 3e catégorie dans /config ; anti-spam (multi-salons + même salon, sanctions configurables) ; vérification (web / réaction / bouton, salon, rôles, sync panneau).
  • Anti-spam runtime : suppression messages dupliqués ; après N suppressions → sanction (timeout 10 min par défaut, ban/kick/warn/none).
  • Vérification runtime : panneau bouton/réaction/web ; queue commands.json ; sync legacy bot/data/servers/ pour lbxmb.fr.
  • Modération rôles en masse via /role.
  • Anti-spam actif si anti-raid + anti-spam activés dans /config > Sécurité.
  • Vérification web/bouton/réaction alignée sur le bot Python.
2026-06-24 13:00 — /config2 : éditeur Container sans modale
  • L'utilisateur souhaite remplacer les modales de configuration des messages (bienvenue, etc.) par une interface Container V2 propre : boutons par paramètre (titre, description, couleur, carte…).
  • Nouvel éditeur unifié (buildEditorContainerPayload) : sections texte à gauche / bouton à droite pour chaque paramètre (état, format embed/simple, titre, description, couleur embed, carte on/off, titre/sous-titre/accent/fond carte, salon, intervalle périodique).
  • Plus de modale sur /config2 : textes modifiés en envoyant un message dans le salon (collector 60 s) ; couleurs via palette de boutons + option hex custom ; toggles instantanés.
  • Ajout d'une config : création avec valeurs par défaut puis ouverture directe de l'éditeur (salon via ChannelSelect conservé uniquement pour ça).
  • Fichiers : fieldEditV2.js, editFlowV2.js, refonte panelsV2.js + routerV2.js.
  • Configuration des messages entièrement dans les Containers V2, navigation cohérente, visuel type « panneau de réglages ».
  • bot-public/src/handlers/config/{fieldEditV2,editFlowV2,panelsV2,routerV2}.js
2026-06-24 12:51 — /config2 : Sections V2 (texte gauche / bouton droite)
  • L'utilisateur souhaite remplacer les menus déroulants de /config2 par des lignes Section Components V2 : texte à gauche, bouton d'action à droite (style DraftBot).
  • panelsV2.js : refonte avec SectionBuilder + TextDisplayBuilder + setButtonAccessory pour la liste des fonctions (arrivée, départ, MP, réguliers), la liste des configurations, le détail entrée/carte et la suppression.
  • /config2 ouvre directement le panneau Messages automatique (4 sections avec bouton « Configurer »).
  • routerV2.js : retrait des handlers StringSelectMenu ; suppression directe via cfg2:remove:one:<section>:<id> ; seul menu conservé = sélection de salon à l'ajout (ChannelSelect).
  • Redémarrage bot-public.
  • UI /config2 alignée sur le modèle texte/bouton horizontal ; plus de menus déroulants pour naviguer entre les options.
  • bot-public/src/handlers/config/panelsV2.js, routerV2.js
  • bot-public/src/commands/owner/config2.js
2026-06-24 08:50 — Bot public : carte dans l'embed, carte configurable, /config2 (Components V2)
  • Message bienvenue/départ configuré en « embed » mais envoyé en message simple : la carte image court-circuitait l'embed.
  • Couleur d'accent de la carte non configurable ; pas de titre/sous-titre personnalisables ; import d'image impossible sans URL.
  • Blockquote > à fiabiliser dans l'embed /config.
  • Demande d'un POC Components V2 (Container).
  • welcomeSender.buildEntryPayload : la carte est désormais intégrée dans l'embed (embed.setImage(attachment://carte.png)) quand type=embed + carte activée ; sinon image en pièce jointe (type simple) ; sinon embed/texte normal.
  • messagePayload.js : ajout de buildEmbed() + parseColor() réutilisables.
  • Carte (welcomeCard.renderWelcomeCard) : accent, titre et sous-titre paramétrables (placeholders appliqués, dont {server}, {count.member}), fond via URL ou fichier local importé.
  • /config : nouveau sous-panneau Carte (activer/désactiver, éditer texte & couleur, importer une image en pièce jointe via collector 60 s, stockage local dans data/cards/<guild>/<id>.<ext>).
2026-06-24 08:35 — Incident : suppression massive de fichiers sources
  • Vers 06:32 UTC (08:32 locale), un grand nombre de fichiers sources du projet ont été supprimés du disque : bot-public/src/, bot-site/src/, .env/package.json/ecosystem.config.cjs des deux bots, plusieurs fichiers web (web/src/app/layout.tsx, web/src/app/globals.css, web/next.config.ts, ~30 dossiers vidés sous web/src/app), ainsi que ce journal.
  • node_modules/, package-lock.json, les builds .next/.next-staging et data/ ont survécu → la prod et les bots tournaient encore depuis la mémoire, mais un redémarrage les aurait fait planter.
  • Cause non identifiée (pas un dépôt git, aucun cron suspect). Coïncide avec le début d'une session agent.
  • Recréation intégrale de bot-public et bot-site à partir de l'historique de conversation.
  • Le web n'a PAS été modifié (contenu des fichiers supprimés non disponible côté agent).
  • Bots opérationnels à nouveau ; web à restaurer séparément depuis une sauvegarde.
  • bot-public/, bot-site/ (recréés), docs/RECAP-TRAVAIL-COMMUNAUTE-2026-04.md (recréé).
2026-06-24 — Profil bot serveur, /rpc, fix threads auto

1. Le profil bot modifiait l'avatar/nom global du bot au lieu du seul pseudo serveur.

2. Demande d'une commande /rpc (User Install) pour simuler une Rich Presence via container.

3. Threads auto : messages supprimés même avec tout autorisé (config legacy require_* interprétée en mode restrictif).

  • Profil bot : applyBotProfile() ne fait plus que member.setNickname() ; UI /config limitée au pseudo serveur + avertissement Discord.
  • /rpc : commande globale User Install + panneau Container V2 (type, chrono, modales texte/images) ; stockage data/user-rpc/<userId>.json ; handlers boutons/modales urpc:*.
  • Threads auto : migration legacy require_* → allow_* au chargement ; détection pièces jointes élargie ; config serveur 1494082227674288168 migrée sur disque.
  • Plus de modification globale du bot via /config profil ; pseudo serveur uniquement.
  • /rpc disponible en installation utilisateur (preview simulée, pas de vrai RPC Discord).
  • Les messages texte, image seule ou avec légende ne sont plus supprimés si les types sont autorisés.
LB'XMB.FR Logo
LB'XMB.FR

LB'XMB.FR is the reference platform for console modding.

Support

  • Donate
  • VIP Premium

Legal

  • Legal notice
  • Terms of use
  • Règlement
  • Credits
  • Changelogs

Our domains

  • lb-c.fr
  • lbxmb.be
  • lbxmb.com
  • lbxmb.eu
  • lbxmb.fr
  • lbxmb.net
  • lbxmb.online
  • lbxmb.org
  • lbxmb.site
  • lbxmb.store
  • lbxmb.xyz

Partners

    © 2026 LB'XMB.FR. Created April 25, 2024. All rights reserved.
    Made with ❤️ for the community.

    forum-group-pages.ts, forum-group-permissions.ts, pages/route.ts, pages/[pageId]/route.ts, channels/route.ts, roles/route.ts, ForumGroupPagesPanel.tsx, ForumGroupRolesPanel.tsx, ForumGroupSettingsModal.tsx, ForumGroupCommunityPanel.tsx

    ### 4. Liste membres Discord + toggle desktop

    #### Contexte / problème

    Barre « MEMBRES — N », rows rounded-lg, plaque full-bleed. Users md:hidden.

    #### Changements

    Fond #2b2d31, w-60, headers rôle Discord, rows ~42px, plaque bandeau bas max 36px. Drawer max 320px. State membersOpen (défaut true). Icône Users Accueil + texte + vocal. md:flex seulement si ouvert.

    #### Fichiers

    ForumGroupCommunityPanel.tsx, ForumGroupHomeView.tsx

    ### 5. Modération vocale mute / casque / déplacer

    #### Contexte / problème

    Bits MUTE_MEMBERS / DEAFEN_MEMBERS / MOVE_MEMBERS jamais appliqués.

    #### Changements

    #### Fichiers

    forum-voice.ts, moderate/route.ts, token/route.ts, ticket-socket.ts, server.js, ForumVoiceSession.tsx, ForumVoiceParticipantMenu.tsx, ForumVoiceCallStage.tsx, ForumVoiceSidebar.tsx, forum/vocal/[channelId]/page.tsx

    ### 6. Messages envoyés deux fois

    #### Contexte / problème

    handleSend ajoutait le message alors que le socket onNew l’avait déjà inséré.

    #### Changements

    Dédup par id + sendingRef anti double POST.

    #### Fichiers

    ForumGroupCommunityPanel.tsx

    #### Déploiement

    BUILD_ID kGgm-wCQr2mmo27TKjl3h. web-prod redémarré (5 workers online).

    • onBackMobile (ArrowLeft md:hidden).
    • Bouton « Vocal / conférence » en édition ; cards lecture Volume2/Radio.
    • Hub par page : forum_group_home PK (group_id, page_id), GET/PATCH ?pageId=.
    • Sélecteur de page en header si plusieurs pages.
    • Colonne is_default ; seed « Serveur » si vide ; suppression de la page défaut refusée.
    • POST channels avec pageId → forum_group_page_channels.
    • forum_group_roles.page_id NULL = rôle serveur ; set = rôle de page. Liste rôles filtrée. ACL pages = rôles serveur uniquement (hors @everyone). GET pages filtré pour le viewer (owner/admin voient tout).
    • Settings Pages : liste pleine largeur + détail (nom, qui peut voir). Layout max-sm comme Rôles.
    • Sidebar : items type Accueil (House / Layers) au lieu de pills. Clic = page + hub.
    • POST /api/forum/voice/channels/[id]/moderate. Créateur (forum_groups.created_by) intouchable mute/deafen.
    • LiveKit tracks + metadata { serverMuted, serverDeafened }. Persistance forum_voice_server_moderation.
    • Socket voice_force_move. Menus participant. Membres connectés sous le salon sidebar.

    #### Changements

    nextSortOrderInCategory seulement si category_id change (texte + vocal).

    #### Fichiers

    channels/[channelId]/route.ts

    ### 4. Accueil + Pages

    #### Contexte / problème

    Pas de hub ni de multi-communautés dans un serveur.

    #### Changements

    #### Fichiers

    forum-group-home.ts, forum-group-pages.ts, home/route.ts, pages/route.ts, pages/[pageId]/route.ts, ForumGroupHomeView.tsx, ForumGroupPagesPanel.tsx, ForumGroupCommunityPanel.tsx, ForumGroupSettingsModal.tsx, forum-group-selfhost.ts

    ### 5. Événements mobile

    #### Contexte / problème

    absolute inset-0 clipé par overflow-hidden.

    #### Changements

    fixed inset-0 z-[100], 100dvh mobile, liste min-h-0 overflow-y-auto.

    #### Fichiers

    ForumGroupEventsModal.tsx

    #### Déploiement

    BUILD_ID 2qgm9JtmWebnSFF4vSAPF. web-prod redémarré (5 workers online).

    • Item Accueil (pas un salon) : bannière, texte markdown, blocs salon / épinglés. API GET/PATCH .../home.
    • Pages max 10, M:N salons et rôles. Switcher sidebar. Salon non assigné = toutes les pages. Settings Participation + Pages.

    Globe en double (salon forum + compteur membres).

    #### Changements

    Salon forum → MessagesSquare. Compteur membres → Users (Lock si privé).

    #### Fichiers

    ForumGroupCommunityPanel.tsx, ForumGroupForumChannelView.tsx

    ### 4. Relief composer

    #### Contexte / problème

    En embedded, barre border-0 bg-transparent.

    #### Changements

    Fond #383a40, bordure légère, ombre interne, rounded-lg.

    #### Fichiers

    MessageComposerBar.tsx

    ### 5. Sujet de salon

    #### Contexte / problème

    Le header affichait topic sans édition ni PATCH.

    #### Changements

    PATCH topic (max 1024). Champ « Sujet » dans Vue d’ensemble. Rechargement via loadChannels après save.

    #### Fichiers

    channels/[channelId]/route.ts, ForumGroupChannelEditModal.tsx, ForumGroupCommunityPanel.tsx

    ### 6. Doublons catégories vocales LBXMB

    #### Contexte / problème

    migrateSocialVoiceToOfficialServer INSERT Vocaux sans snowflake si aucune cat. nommée vocal/voice, puis le sync Discord en ajoute d’autres.

    #### Changements

    Ne plus créer Vocaux s’il existe déjà une cat. avec vocaux ou snowflake Discord. Fusion / suppression des Vocaux vides sans snowflake. Général / Besoin d’aide rattachés à la cat. vocale retenue.

    #### Fichiers

    forum-voice-social-migrate.ts

    ### 7. Planning → Événements

    #### Contexte / problème

    Titre « Planning », formulaire collé sous la liste, pas de tri en cours / à venir.

    #### Changements

    Titre Événements. Bouton « Créer un événement » en haut. Liste En cours → À venir → Passés repliés. Création / édition en sous-écran. Cover URL optionnelle.

    #### Fichiers

    ForumGroupEventsModal.tsx, ForumGroupCommunityPanel.tsx

    ### 8. Markdown Discord dans le chat

    #### Contexte / problème

    LinkifiedText : URLs + @ + emojis seulement.

    #### Changements

    parseDiscordMarkdown après tokens d’expression (salons, MP, tickets). Listes - , --surligné-- → <mark>, ~~barré~~ → <s>, blocs ` . CSS discord-ul / discord-pre.

    #### Fichiers

    markdown.ts, MessageLinkEmbeds.tsx, globals.css

    #### Déploiement

    BUILD_ID 3G9Q46SQGLdcy8h_LgoPV. web-prod redémarré (5 workers online).

    • Carte ForumGroupServerProfileCard : bannière, logo, Public/Privé, connectés/total, quitter / signaler / avis, créateur + date, grille d’emojis.
    • Table forum_group_reviews + API GET/POST .../groups/[slug]/reviews (1 avis / membre).
    • Clic sur le nom du serveur (et menu « Voir le profil ») ouvre cette carte. L’onglet settings reste l’éditeur.
    • Pointeur coarse : draggable={false} ; timer 1 s sans bouger → menu Épingler / Modifier / Supprimer.
    • Souris : clic droit + drag inchangés. Même logique sur les catégories.

    SiteAppRailUserCard en bas du rail : bannière profil, avatar qui dépasse, mute / casque / notif / paramètres. Préférence mute persistée. Anciennes barres retirées.

    #### Fichiers

    SiteAppRailUserCard.tsx, SiteAppServerRail.tsx, SiteAppShell.tsx, ForumVoiceSession.tsx, site-app-voice-prefs.ts, SiteAppSettingsModal.tsx, ForumGroupsShell.tsx, SiteAppSidebar.tsx

    ### 4. Long-press 1s / 2s

    #### Contexte / problème

    420 ms trop court, un micro-mouvement lançait le drag.

    #### Changements

    1 s → menu. 2 s maintenu → drag. Mouvement après le menu n’annule plus le menu.

    #### Fichiers

    SiteAppServerRailList.tsx

    ### 5. Logs d’audit

    #### Contexte / problème

    Filtre texte role.create.

    #### Changements

    Select groupé FR. Meta group.update (nom, photo, bannière, visibilité). Log member.roles si les membres d’un rôle changent.

    #### Fichiers

    forum-group-audit-labels.ts, ForumGroupSettingsModal.tsx, groups/[slug]/route.ts, roles/[roleId]/route.ts

    ### 6. Gérer un salon

    #### Contexte / problème

    Select catégorie inline dans les settings.

    #### Changements

    Bouton Gérer → Modifier le salon / Changer de catégorie.

    #### Fichiers

    ForumGroupSettingsModal.tsx

    ### 7. Icône de rôle

    #### Contexte / problème

    Champ emoji/texte en plus de l’image.

    #### Changements

    Champ retiré. Icône = image uniquement.

    #### Fichiers

    ForumGroupRolesPanel.tsx

    ### 8. Invitations

    #### Contexte / problème

    Copier seulement.

    #### Changements

    PATCH/DELETE invites/[code]. Boutons Modifier / Supprimer.

    #### Fichiers

    invites/[code]/route.ts, ForumGroupInviteCreateModal.tsx, ForumGroupSettingsModal.tsx, forum-group-selfhost.ts

    ### 9. Picker emojis

    #### Contexte / problème

    Sous-onglets. Serveurs vides affichés.

    #### Changements

    3 onglets plats. Rail serveurs filtré par compteurs emoji/sticker (GET groups?mine=1).

    #### Fichiers

    MessageComposerBar.tsx, groups/route.ts

    #### Déploiement

    BUILD_ID 4pxMtfsbxU03Fw7Y-GxBK. web-prod redémarré (5 workers online).

    • En-tête : icône + nom + compteur. Lignes : avatar + pseudo seulement.
    • Sections uniquement pour rôles hoistés ; le reste va dans « En ligne ».

    ### 3. Salon Scroll (TikTok)

    #### Contexte / problème

    Pas de fil vertical image/vidéo.

    #### Changements

    #### Impact visible / technique

    Nouveau type de salon dans Créer un salon.

    #### Fichiers

    forum-group-reels.ts, reels/route.ts, vote|view|comments/route.ts, ForumGroupReelsChannelView.tsx, channels/route.ts, ForumGroupCommunityPanel.tsx

    ### 4. Composer 10 lignes

    #### Contexte / problème

    Plafond 5 lignes (112 px), isMobile non passé.

    #### Changements

    Desktop 10×22 px, mobile 10×18 px. Enter mobile = nouvelle ligne.

    #### Fichiers

    ComposeTextarea.tsx, MessageComposerBar.tsx, ForumGroupCommunityPanel.tsx

    ### 5. Long-press dossier

    #### Contexte / problème

    Le long-press tactile lançait un drag, pas le menu Modifier.

    #### Changements

    Timer 420 ms sans mouvement → menu. Mouvement ensuite → drag (réordonner).

    #### Fichiers

    SiteAppServerRailList.tsx, SiteAppServerRail.tsx

    ### 6. Fix build Buffer reels + déploiement

    #### Contexte / problème

    tsc : Buffer<ArrayBufferLike> non assignable à Buffer<ArrayBuffer> dans POST reels (sanitize sharp).

    #### Changements

    let out: Buffer = raw dans reels/route.ts.

    #### Impact visible / technique

    Build prod OK. BUILD_ID gxANBAoqMpmvrWvrJXZbF. web-prod redémarré (5 workers online).

    #### Fichiers

    reels/route.ts

    • Colonne reply_to_message_id ; POST/GET messages + handleSend envoient replyToMessageId.
    • Card : bg-sky-500/[0.12] + barre gauche si @pseudo ou réponse vers soi.
    • Token @pseudo coloré (classe .mention). Aperçu de réponse sur le message.
    • Composer vide : Micro à la place d’Envoyer. Texte ou fichier → pastille #5865f2 + ArrowUp.
    • MediaRecorder → POST multipart ; lecture VoiceMessagePlayer.
    • channel_kind = reels ; création « Scroll ».
    • Tables posts / votes / vues / commentaires.
    • Vue snap verticale, like/dislike, vues, commentaires, publication multi-fichiers.

    ### 3. Plaque membre PNG/GIF

    #### Contexte / problème

    Pas de nameplate par serveur (fond de ligne membre / carte profil).

    #### Changements

    #### Impact visible / technique

    Chaque membre peut poser une plaque animée visible dans la liste et le popover.

    #### Fichiers

    members/me/plaque/route.ts, members/route.ts, UserProfilePopover.tsx, ForumGroupCommunityPanel.tsx, use-forum-social.ts, forum-group-selfhost.ts

    ### 4. Double Retour — rôles mobile

    #### Contexte / problème

    Header modal « Retour » + Retour de l’éditeur rôle.

    #### Changements

    #### Impact visible / technique

    Un seul bouton Retour à l’écran.

    #### Fichiers

    ForumGroupSettingsModal.tsx, ForumGroupRolesPanel.tsx

    ### 5. Bannière profil dupliquée

    #### Contexte / problème

    Aperçu lecture seule + zone d’upload affichaient la même image.

    #### Changements

    Suppression de l’aperçu h-28 ; seule la zone « Bannière » reste.

    #### Impact visible / technique

    Plus de doublon dans Profil du serveur.

    #### Fichiers

    ForumGroupSettingsModal.tsx

    • MessageReactions : SmilePlus toujours visible.
    • toggleChannelReaction : update optimiste + rollback si l’API échoue.
    • POST réactions : ADD_REACTIONS + channelKind: "text" (annonces = salon texte).
    • Ligne stats Discord : ❤️ / 💔 cliquables → même toggle.
    • Tag retiré de « Profil du serveur ». Nav Tag du serveur (texte max 5, icône, style).
    • Colonne forum_groups.tag_style : bronze | argent (défaut) | or | diamond | ruby | platine | emeraude.
    • ServerTagBadge : dégradé selon tagStyle. PATCH / GET / summary / vanity / primary-tag.
    • forum_group_members.plaque_url.
    • POST/PATCH …/members/me/plaque (scan + sanitize, GIF conservé, 4 Mo, PNG/GIF/WebP/JPEG).
    • Liste membres : fond object-cover + voile ; clic toute la ligne → profil.
    • Carte profil : plaque prioritaire sur users.banner, bandeau h-24/h-28, « Changer la plaque » si soi ; mobile = bottom sheet.
    • Header modal masqué sur mobile si nav === "roles" ; overlay inset-0.
    • Liste des rôles : un Retour vers les onglets. Éditeur : un Retour vers la liste.
    • GET /api/forum/voice/channels : salons officiels Général + Besoin d'aide (mêmes ids que /app). POST social group_id NULL réservé aux superusers. Lobby : plus de « Créer mon canal » (sauf superuser).
    • migrateSocialVoiceToOfficialServer : assure les 2 salons système sur le groupe officiel, rattache les NULL restants, désactive les extras.
    • dev-test discordChannelId = 1510721137422631123 + ensureBridgeDiscordSnowflakes au schema/ensure.
    • Test overwrite : guild MANAGE_MESSAGES allow + deny salon → false. DELETE messages via resolveChannelPermission(MANAGE_MESSAGES).
    • Settings : salons imbriqués cat→salons ; panneau min-h-0 flex-1 overflow-y-auto ; menu ⋯ portail document.body z-[200] ; Kick/Ban masqués pour soi.
    • Rôles mobile : liste seule, overlay onglets scrollable + Retour. Desktop inchangé.
    • Logs : placeholder « Utilisateurs », labels FR, diffs meta before/after (PATCH channel/role).
    • Bans : nav si BAN_MEMBERS/ADMIN ; plus de raccourci membres ; 1 carte/ligne → modal raison Fermer/Révoquer ; durée 1h/1j/7j/30j/permanent + notify ; expires_at contrôlé à l'accès.

    #### Fichiers

    forum-group-expressions.ts, forum-expression-audio-trim.ts, ForumGroupExpressionsPanel.tsx, expressions/route.ts

    ### 3. Picker Emojis / Autocollants

    #### Contexte / problème

    Un onglet « Serveur » limité au slug courant, insertion en ![name](url) (lien bleu).

    #### Changements

    #### Impact visible / technique

    On peut insérer emojis/stickers de n’importe quel serveur dont on est membre, sans lien markdown.

    #### Fichiers

    MessageComposerBar.tsx, forum-expression-tokens.ts

    ### 4. Rendu sans liens bleus

    #### Contexte / problème

    Les URLs d’expressions devenaient des liens / embeds.

    #### Changements

    #### Impact visible / technique

    Les emojis/stickers s’affichent en inline dans le chat (dont ForumGroupCommunityPanel).

    #### Fichiers

    MessageLinkEmbeds.tsx, forum-expression-tokens.ts

    • Modal d’ajout : viewRoleIds et useRoleIds (vide = tout le monde).
    • POST expressions/route.ts : canView pour view, canUse+canView pour use. Pas de PATCH ACL côté client.
    • EXPRESSION_LIMITS : emoji/sticker 4 Mio, son ~8 Mio, maxDurationMs 10000.
    • UI : si durée > 10 s, modal curseur (fenêtre 10 s), decode Web Audio, export WAV, upload avec durationMs.
    • Serveur refuse durationMs > 10000.
    • Onglets Emojis | Autocollants ; sous-onglets Classiques | Serveur.
    • Rail d’avatars (/api/forum-social/groups?mine=1), expressions canView du serveur choisi.
    • Insertion tokens e/s via forum-expression-tokens.ts.
    • MessageWithLinkEmbeds / LinkifiedText : tokens e/s et restes ![name](url) vers /api/uploads/groups/expressions/ → <img> 22px / 96px.
    • Ces URLs sont exclues de extractUrls (pas d’embed).
  • Membres API : colorMode / colorSecondary ; chat/liste utilisent forumRoleColorProps (dégradés).
  • Tag serveur argenté, rail mobile masquée dans un salon, miniature forum à droite (déjà en place).
  • Token vocal → startVoiceSession ; leave → endVoiceSession.
  • Audit member.leave / member.kick sur quitter / expulser.
  • UI Recharts (légende FR, totaux, sélecteur 7/14/30 j) dans les paramètres.
  • Formats API rentry (create/PUT/GET) + affichage public via GuideReadmeView.
  • Lecture interactive (GuideChapterView) : boutons de choix, image floutée jusqu’au clic.
  • Métadonnées compactes (ressources/guides requis repliés). Collage URL → lien, collage/drop image conservé.
  • ### Blockers / notes

    • Flag permission eclipse + helpers hasEclipseSlot / hasEclipseToken / canCreateHostedGroup (vip-tier.ts, vip-group-create.ts).
    • Gate création : hébergé = eclipse ou vip_premium (legacy / Stripe) ; self-host inchangé (skip gate API si hostingMode=self_hosted).
    • Stripe : plan eclipse dans /api/vip/checkout ; activate ajoute eclipse (sans vip_subscriptions pour ne pas activer Premium).
    • /api/vip/status expose hasEclipse ; tier public peut être eclipse.
    • Marketing : carte Éclipse (1er perk = créer serveur hébergé) dans SiteAppDonatePanel + grille VIP page (ECLIPSE_ADV, i18n fr/en).
    • Rôle dashboard / role-styles : eclipse.
    • Long-press pointer (touch/pen) dans SiteAppServerRailList : drag dossiers/serveurs, ghost, drop via data-rail-drop.
    • HTML5 DnD desktop conservé.
    • Rail toujours visible en mode serveur mobile (hideRailOnMobile limité à home + main ouvert) → dossiers accessibles.
    • Messages : pseudo n’ouvre plus le popover (avatar seul).
    • Liste membres : row non cliquable ; avatar seul ouvre UserProfilePopover.
    • libretranslate.ts : mask non-latin ([[Nn]]) après emojis ; pas d’appel API sans run [A-Za-z]+ ; unmask après.
    • TranslatedText : early-return sans latin ; compatible jetons emoji/N.
    • Expiration Éclipse non auto-strippée (pas de ligne vip_subscriptions dédiée) — flag eclipse reste jusqu’à retrait manuel / process futur.
    • Prix Éclipse = 4,95 € (même montant que VIP mensuel) ; pas de produit Stripe Price ID fixe (price_data ad-hoc).
    • serverChannelFocused toujours câblé mais plus utilisé pour masquer la rail.

    ### Blockers / notes

    • Colonne content_embed VARCHAR(32) NULL sur forum_group_channels (ensure dans forum-voice + forum-official-server).
    • Soft-migrate one-shot des salons nommés guides/ressources/boutique (softMigrateContentEmbedChannels au GET channels).
    • API GET/PATCH channels expose contentEmbed: null | guides | ressources | boutique.
    • ForumGroupChannelEditModal : select « Contenu intégré ».
    • ForumGroupContentEmbedPanel : catalogues guides/ressources + SiteAppCatalogPanel boutique + SiteAppDetailPanel.
    • ForumGroupCommunityPanel : si contentEmbed → panneau embed à la place du chat/forum.
    • ForumGroupForumChannelView : colonne unique (plus de sm:grid-cols-2), vignette carrée = 1ʳᵉ image des attachments.
    • Tables forum_group_channel_tags + forum_group_forum_post_tags (ensure schema).
    • API CRUD /channels/[id]/tags (+ [tagId] PATCH/DELETE).
    • Liste/création posts : tags multi-select ; list/detail posts renvoient tags + attachments.
    • Modal édition salon forum : onglet Tags.
    • SiteAppSettingsModal : portal fullscreen (comme settings serveur), nav groupée Compte / Connectivité / Appli.
    • Réutilise SecuritySettings, AssociatedAccounts, NotificationSettings, LanguageSwitcher, SiteAppVoiceSettingsPanel + stubs (QR, appareil, intégrations, accessibilité, discuter).
    • Apparence : conserve uiScale / messageFontSize.
    • Helper site-profile-grades.ts : filtre Fondateur / Administrateur / Modérateur depuis /api/users/[id].
    • Affichage via PermissionRoleBadge dans UserProfilePopover + SiteAppProfileModal.
    • Scanner QR / Appareil / Intégrations / Accessibilité / Discuter = stubs.
    • Soft-migrate content_embed ne crée pas les salons manquants (met à jour seulement si slug/nom match et content_embed NULL).
    • Tags API non proxifiés côté agent self-host au-delà du chemin générique maybeProxy.

    ### Blockers / notes

    • Helpers : forumGroupVanityInviteUrl → https://{domain}/ ; forumGroupInvitePublicUrl(code) toujours sur lbxmb.fr/invite/g/{code} (domaine custom ignoré pour les codes).
    • GET /api/forum-social/invite-domains/[host] → résumé serveur public.
    • Page /invite/host/[host] + rewrite edge dans proxy.ts : Host hors plateforme + path / → page join.
    • Aide invites dans ForumGroupSettingsModal mise à jour ; copie des codes = URL plateforme.
    • MessageLinkEmbeds : URLs racine / hosts nus → embed vanity (API invite-domains) ; /invite/g/{code} conservé.
    • GET .../members : photo, displayName (discord_username ou pseudo), createdAt, joinedAt, liste roles.
    • Settings membres : avatar, dates, rôles, menu ⋯ (copier pseudo, gérer rôles → RolesPanel, kick, ban, rename nick → toast « bientôt »).
    • UserProfilePopover : createdAt + joinedAt optionnel (passé depuis le panneau communauté).
    • Toast + message d’erreur si POST échoue (plus de if (!success) return silencieux).
    • Plus de double PATCH ACL quand roleIds déjà gérés au POST.
    • accept="image/*", bouton Créer avec état busy « Envoi… ».
    • forum retiré de SITE_APP_TABS / labels ; ?tab=forum|social → fallback suivis.
    • Nettoyage SiteAppSidebar / SiteAppShell (plus de SiteAppForumPanel dans le shell). Autres onglets inchangés.
    • DNS/CNAME Cloudflare vers lbxmb.fr toujours requis pour que le Host vanity atteigne l’app.
    • Pas de colonne nick serveur → rename = toast « bientôt ».
    • displayName = discord_username si présent, sinon pseudo (pas de champ display_name dédié).
  • ForumGroupSettingsModal : rendu via createPortal(document.body) + fixed inset-0 z-[100] ; aide bannière 960×540 (16:9) ; DnD HTML5 catégories/salons (flèches conservées) via PATCH reorder/move.
  • Nouveau ColorPicker (swatches + hex + RGB) ; modal édition dossier rail utilise ColorPicker + upload image icône.
  • API POST /api/forum-social/me/server-rail/folder-icon (auth, PNG/WebP, uploads) ; URL stockée dans folder.icon (layout JSON, slice 512).
  • Thème app : uiScale compact|normal|large + messageFontSize sm|md|lg (localStorage) ; CSS vars --app-ui-scale / --app-message-font-size appliquées sur le shell ; contrôles Apparence dans SiteAppSettingsModal.
  • saveForumGroupTagIcon (pattern rôle) ; PATCH groupe accepte tag (max 5), tagIcon multipart / tagIconUrl / removeTagIcon.
  • APIs GET/PUT /api/forum-social/me/primary-tag et GET/PUT /api/forum-social/me/server-rail.
  • Messages salon : jointure tag primaire auteur dans le payload (primaryServerTag) ; /api/users/[id] expose aussi le champ.
  • UI : ServerTagBadge (chip + popover résumé/Rejoindre) dans messages, UserProfilePopover, SiteAppProfileModal.
  • ForumGroupSettingsModal overview : tag maxlength 5 + upload/preview icône.
  • SiteAppSettingsModal Profil : dropdown tag primaire (fusionné avec bannière Vague 2).
  • SiteAppServerRail + SiteAppServerRailList : lbxmb-fr épinglé, DnD reorder, drop serveur→serveur crée dossier, ctx menu Modifier/Supprimer dossier, persist PUT.
    • Schéma forum_groups.invite_domain VARCHAR(255) NULL via ensureColumn + index unique uq_forum_groups_invite_domain (ignore si échec).
    • Helpers normalizeInviteDomain + forumGroupInvitePublicUrl(code, inviteDomain?) → https://{domain}/invite/g/{code} si défini.
    • API GET/PATCH groups/[slug] : lit/écrit inviteDomain (MANAGE_GROUP) ; 409 si domaine déjà pris.
    • Invites GET/POST + preview /invites/[code] : URLs avec domaine custom du groupe.
    • Settings → Invitations : champ domaine + aide CNAME Cloudflare ; liste/copie utilisent l'URL custom.
    • MessageLinkEmbeds.parseForumInviteLink : /invite/g/{code} reconnu sur n'importe quel host ; /app?server= réservé aux hosts lbxmb.
    • Middleware/proxy : pas d'allowlist host bloquante (seul redirect www.lbxmb.fr) — un CNAME Cloudflare proxy vers l'app suffit pour /invite/g/[code]. API invite-domains/[host] non ajoutée (path-based suffisant).
    • SiteAppSettingsModal section Profil : upload/preview/suppression via /api/profil/banner + crop 3:1 (miroir /parametres).
    • UserProfilePopover + SiteAppProfileModal : affichent banner / bannerUrl renvoyés par /api/users/[id].
    • Nouveau ServerContextMenu.tsx : clés localStorage favoris/mute + buildServerContextMenuItems (profil, invite, favori, mute, copier ID, signaler, quitter sauf officiel).
    • SiteAppServerRail branché sur le builder partagé.
    • ForumGroupCommunityPanel : clic droit sur en-tête nom/avatar → mêmes actions + modals invite / profil serveur / leave / report.
  • ForumGroupSettingsModal : passe hideTabs sur les navs emojis / stickers / soundboard.
  • API POST .../expressions : accepte roleIds (JSON array) et appelle upsertExpressionAclRole (canView+canUse) après insert ; sélection vide = ACL vide (défaut GET : tout le monde).
  • MessageComposerBar : props serverSlug, enableEmojiPicker ; bouton Smile + popover Classiques (emoji-picker-react) / Serveur (![name](url) markdown image).
  • ForumGroupCommunityPanel : wire picker (serverSlug={slug}) ; DnD catégories (application/x-lbxmb-category, états dragCategory / dropCategoryTarget, PATCH { type: "reorder", categories: [...] }) sans casser le DnD salons.
  • libretranslate.ts : unmask [E0] / [ E0 ] ; si jetons résiduels après unmask → renvoyer le texte original.
  • TranslatedText : garde l'original si [[E / [E+digit dans la traduction ; skip si texte hors-emoji < 2 ou pictographiques > 50 % de la longueur.
  • consoles-config.ts : catégories Outils et Emulateurs ajoutées pour chaque console ; RESOURCE_SUBCATEGORIES étendu (Outils / Emulateurs).
  • libretranslate.ts : jetons emoji ASCII [[E0]] + unmask tolérant (formes altérées LBXMB EMOJI) ; skip API si texte hors-emoji vide.
  • TranslatedText.tsx : pas d'appel translate si le texte n'a que des emojis / espaces.
  • ForumGroupCommunityPanel.tsx : suppression modal « Déplacer… » + états associés ; déplacement = drag-and-drop uniquement.
  • API GET/POST .../groups/[slug]/invites : lit/écrit expiresAt, maxUses, grantRoleIds ; retourne l'URL publique https://lbxmb.fr/invite/g/{code}.
  • API GET/POST /api/forum-social/invites/[code] : preview publique + redeem/join (refuse expiré / max uses, incrémente uses, ajoute membre, assigne grant_role_ids, contourne la restriction « open only » du join classique).
  • API GET .../groups/[slug]/summary : résumé public pour embeds ?server=slug.
  • Page /invite/g/[code] (+ layout) : infos serveur + CTA rejoindre.
  • UI ForumGroupInviteCreateModal : durées 1h / 1j / 7j / 30j / jamais, max uses, multi-sélection rôles, lien + copie.
  • ForumGroupSettingsModal : nav en sections (Nom du serveur / Expression / Utilisateurs / Modération) ; stubs Participation & Analyse ; panneau Membres ; Expression via sous-entrées Emojis / Autocollants / Soundboard ; Invitations branchées sur le modal de création.
  • SiteAppServerRail : « Créer une invitation » ouvre le modal (plus de simple copie /app?server=).
  • MessageLinkEmbeds : détection /invite/g/{code} et /app?server= (domaine lbxmb.fr) → carte avatar / nom / membres / badge rôles / CTA Rejoindre.
  • scripts/test-forum-group-permissions.mjs : lanceur Node (hook registerHooks ajoutant .ts à la résolution) → les sources gardent leurs imports sans extension.
  • package.json : script test:permissions.
  • Tests : 2 scénarios ajoutés (overwrite @everyone du salon quand tous les rôles héritent, puis prise de contrôle par un overwrite de rôle ; bypass ADMINISTRATOR malgré un refus membre) → 6 au total.
  • ForumGroupChannelEditModal : bascule cycle → TriStateToggle, aide reformulée (refuser / hériter / autoriser + rappel de la priorité).
  • UI ForumGroupRolesPanel : zone upload + aperçu ; RoleLabel affiche image ou emoji + nom coloré ; mode balance retiré (soft-migration → gradient) ; CSS .lbx-role-balance déjà absent.
  • Permissions / hoist / mentionnable : PermissionToggle bi-état (gris / bleu #5865f2) ; overwrites salon via TriStateToggle (rouge / gris / bleu).
  • Hiérarchie pure dans forum-group-permissions-hierarchy.ts branchée sur resolveUserPermissionBits / resolveChannelPermission / batch : membre → rôles haut→bas → @everyone → bits guilde.
  • Clic droit liste rôles : Modifier / Accorder (onglet Membres + focus recherche) / Supprimer (ConfirmDialog).
  • Tests forum-group-permissions.resolve.test.ts (bun test) : deny bas+allow haut, everyone seul, member deny vs role allow.
  • DnD HTML5 sur la liste (positions réécrites 1..N) ; @everyone non déplaçable et verrouillé en bas ; drop sur @everyone/zone vide = fin de liste.
  • Membres : liste des membres du rôle (retrait unitaire) + recherche et multi-ajout (cases + bouton « Ajouter (n) »).
  • Suppression rôle via ConfirmDialog (plus de window.confirm).
  • ForumGroupSettingsModal.tsx : onglet Rôles délégué au panneau en pleine hauteur ; tout l'état rôles retiré du modal ; autres onglets inchangés.
  • Schéma forum_group_roles : color_mode (solid|gradient|balance|rainbow) + color_secondary via ensureColumn ; helpers normalizeRoleColorMode / normalizeRoleColor.
  • API rôles : colorMode / colorSecondary exposés en GET/POST/PATCH ; nouveau PATCH /roles { type:"reorder", roles:[{id,position}] } (audit role.reorder, @everyone ignoré) + fallback client PATCH par rôle.
  • CSS .lbx-role-gradient|balance|rainbow (texte en dégradé, animations lentes) avec prefers-reduced-motion.
  • UserProfilePopover ancré (messages + membres), sans overlay assombrissant.
  • Bridge : username webhook unique invisible + claim/filtre contenu doublon 30s.
  • Rôles settings : onglets Affichage / Permissions / Membres, DnD positions, couleurs solid/gradient/balance/rainbow, ConfirmDialog delete (ForumGroupSettingsModal + CSS .lbx-role-*).
  • TranslatedText + /api/translate sur noms salons.
  • Recherche rapide Ctrl/Cmd+K (SiteAppQuickSearch + /api/forum-social/search).
  • Migration vocaux group_id IS NULL → serveur officiel.
  • Resize largeur salons (vocal + sidebar serveur) desktop.
  • VoiceStageErrorBoundary + doc Nativefier.
  • Settings Expression (emojis / stickers / soundboard + ACL rôles).
  • Header serveur : icône Planning + ForumGroupEventsModal (CRUD + RSVP).
  • Poll bot : ignore aussi processingIds (en plus de seenDiscordIds).
  • Libération du claim si canal/thread non mappé ou erreur.
  • Liste /app : tri explicite par sort_order dans chaque catégorie.
  • Collation JOIN bridge corrigée ; author_id site = users.user_id aussi en inbound Discord.
  • Config community_bridge_map.json + community-bridge-map.ts (7 salons, kinds forum/text, slugs catégories site).
  • Upsert salons /app group lbxmb-fr (IDs Discord figés) + tables bridge (forum_group_forum_posts/comments, community_bridge_threads/messages).
  • Superusers Default.xex / interverti : membership admin + rôle Staff LBXMB (ALL_PERMISSIONS) + bypass loadGroupAccessCtx sur lbxmb-fr.
  • bidirectional_sync_config.json mis à jour avec les nouveaux snowflakes.
  • APIs …/channels/:id/forum-posts (+ détail/réponses).
  • UI ForumGroupForumChannelView : grille de posts → fil (OP + replies) + PJ.
  • Salons channel_kind=forum n’utilisent plus le chat linéaire.
  • Module bot-forum-bridge/src/communityBridge.js : outbound poll + inbound messageCreate/threadCreate, webhooks username/avatar, anti-boucle (IDs + ignore webhooks bot), poll REST hors-sujet.
  • API interne /api/internal/community-bridge (GET outbound / POST actions Discord + ack + mirror site→app).
  • Ping bridge depuis création messages /app, posts forum /app, threads/réponses forum site.
  • Auteurs Discord non liés → meta ghost + badge « Compte Discord · non inscrit sur le site ».
  • <:name:id> / <a:name:id> → images CDN Discord côté site.
  • 7 salons bridge actifs sur group_id=9 (entraide#36, jeux-video#51 … hors-sujet#56).
  • bot-forum-bridge health : community.running=true, 7 salons.
  • Sync live à partir du déploiement (pas d’import historique massif).
  • Sync live Discord (GET /guilds/{id}/roles|channels) → rôles, catégories, salons texte/annonce/forum/media, vocaux/stage, overwrites rôle.
  • Colonnes discord_snowflake, channel_kind, topic, nsfw, rate_limit_per_user, discord_type, discord_guild_id, discord_synced_at.
  • Auto-join à chaque GET /api/forum-social/groups (mine/discovery) ; rail pin officiel ; leave/delete bloqués.
  • UI : icônes announcement/forum, topic en header salon, NSFW badge.
  • API admin POST /api/forum-social/groups/official/sync-discord + script web/scripts/sync-official-lbxmb-group.ts.
  • Schéma plateforme : remote_agent_url, remote_agent_token_enc, data_hosting_mode (platform|agent).
  • Mint JWT aud=selfhost-agent + BFF maybeProxySelfHostAgent sur routes groups (channels, messages, roles, bans, …).
  • Webhooks internes : /api/internal/selfhost/realtime, /api/internal/selfhost/ban-sync.
  • Heartbeat accepte token agent ou clé LiveKit.
  • UI création / réglages : URL agent + affichage one-shot AGENT_REGISTER_TOKEN.
  • Join/leave : membership référence plateforme + sync agent.
    • Unification URL avatar via absoluteUploadUrl + fallback CDN Discord (discord_id).
    • prepareDiscordWebhookAvatar (bot-site) : fetch image, conversion webp→PNG (sharp), data URI à la création webhook (Discord ignore souvent .webp).
    • Off-by-one dans forumWebTranslateHandler : custom_id = forum_web_react:{threadId}:heart|broken → lecture parts[1] / parts[2] (avant : [2]/[3]).
    • Restart bot-public.
    • libreTranslate (web + bot-public + bot-site) : si source=auto → detectLanguage ; si détecté === cible → texte inchangé (pas d’appel /translate).
    • UX bot : message « C’est déjà traduit en … » (alreadyTranslatedMessage) sur autotrad / custom / translateForInteraction.
    • Schéma forum_groups : hosting_mode, remote_livekit_url, clés API chiffrées, remote_status, last_heartbeat_at.
    • Création / réglages serveur : option Auto-héberger + URL/clés.
    • Token vocal : mint JWT avec clés remote + url = remote_livekit_url (CSP connect-src déjà wss:).
    • Pack Docker infra/self-host-voice/ (compose LiveKit + Coturn, README, healthcheck).
    • API heartbeat optionnelle POST .../selfhost-heartbeat (Bearer = API key LiveKit).
    • Deploy web-prod via deploy.sh.
  • Dates stables UTC (lib/stable-date.ts) : Footer copyright, HomeFeedCarousel, Testimonials.
  • Feed : extrait texte puis Markdown/polls dynamiques au viewport.
  • MessageBell monté seulement à l’ouverture (plus de socket.io dès auth).
  • Partners : MountWhenVisible (pas de fan-out Discord hors écran).
  • Header : prefetch={false} logo/login.
  • Build + restart web-prod.
  • Restart lbxmb-livekit / lbxmb-coturn (nodeIP confirmé .62).
  • web/.env.local + bot-forum-bridge/.env : LIVEKIT_USE_CLOUD=0, wss://lbxmb.fr/livekit, clés APIforum…, TURN_HOST=151.240.100.62, NEXT_PUBLIC_E2EE_VOICE=1.
  • web/server.js : force aussi NEXT_PUBLIC_E2EE_VOICE depuis .env.local.
  • ecosystem.config.js : défauts TURN Canaux + LIVEKIT_USE_CLOUD=0.
  • Restart web-prod + bot-forum-bridge + pm2 save.
  • Slash ouvre directement une modale (type + membre + raison + durée).
  • Unban : après modal → select des bannis (raison déjà saisie).
  • Titre container : # :scales: Appel de sanctions | <@&1533535460213784637>.
  • allowedMentions: { roles: [...] } à la 1ʳᵉ publication seulement.
  • KV/CID visibles sur /boutique ; salon Discord à jour ; /sanction modal + ping rôle.
  • En cas d’erreur API, la modale reste ouverte au lieu de se fermer silencieusement.
  • Les options/compléments sont éditables normalement à la création et à la modification.
  • La confirmation de suppression dans dashboard → boutique s’affiche correctement au centre de l’écran.
  • web/src/components/forum/ForumPollComposer.tsx, ForumPollBlock.tsx
  • web/src/app/forum/preview/page.tsx
  • web/src/app/api/forum-social/thread/create/route.ts
  • web/src/app/api/forum-social/thread/[id]/poll-vote/route.ts
  • web/src/app/api/internal/forum/poll-vote/route.ts, poll-close/route.ts
  • bot-public/src/commands/util/sondage.js, lib/forumPollBridge.js, lib/internalHttpServer.js, handlers/polls/pollScheduler.js
  • bot-site/src/lib/forumSyncConfig.js, forumAnnouncementPost.js
  • docs/RECAP-TRAVAIL-COMMUNAUTE-2026-04.md
  • bot-public/src/handlers/config/routerCommunity.js
  • docs/RECAP-TRAVAIL-COMMUNAUTE-2026-04.md
  • Callback applique ces flags (blocage multi-IP, filtre ISP FR, refus mobile si OFF).
  • Autres serveurs : parcours vérif autonome sur leur page ; règlement LB'XMB inchangé sur /commencer.
  • Admins peuvent affiner la politique IP/ISP par serveur.
  • web/src/components/verify/LegalAcceptCheckboxes.tsx
  • web/src/lib/legal-accept.ts, web/src/app/api/verify/legal-accept/route.ts
  • web/src/app/api/verify/discord/authorize/route.ts
  • web/src/lib/verify-oauth-callback-logic.ts
  • web/src/app/verify/[id]/VerifyClient.tsx
  • web/lib/allowed-isps.cjs, web/src/lib/allowed-isps.ts
  • web/src/lib/verify-server-config.ts
  • bot-public/src/lib/securityConfig.js
  • bot-public/src/handlers/config/panelsSecurity.js, routerSecurity.js
  • docs/RECAP-TRAVAIL-COMMUNAUTE-2026-04.md
  • Les membres voient un vrai message d’erreur s’il faut réessayer (plus de « terminé » trompeur).
  • Moins d’échecs partiels sous charge Discord.
  • bot-site/src/lib/discordRest.js
  • bot-site/src/lib/commencerChannelAccess.js
  • bot-site/src/lib/commencerCategories.js
  • bot-site/src/index.js
  • web/src/lib/discord-bot-site.ts
  • web/src/app/api/commencer/route.ts
  • web/src/app/api/roles/route.ts
  • bot-public/src/handlers/moderation/communitySanctionHandler.js
  • bot-public/src/handlers/moderation/communitySanctionScheduler.js (nouveau)
  • bot-public/src/events/client/ready.js
  • bot-public/src/commands/moderation/sanction.js
  • bot-public/src/handlers/moderation/communitySanctionHandler.js
  • Tout membre peut proposer une sanction communautaire (commande publique, synchro guild via DEFAULT_COMMANDS).
  • Le bot doit avoir les permissions Ban / Moderate Members sur le serveur pour appliquer le résultat du vote.
  • bot-public redémarré (PM2) ; commande sanction chargée.
  • bot-public/src/commands/moderation/sanction.js (nouveau)
  • bot-public/src/handlers/moderation/communitySanctionHandler.js (nouveau)
  • bot-public/src/lib/moderation/communitySanctionStore.js (nouveau)
  • bot-public/src/events/interaction/interactionCreate.js
  • bot-public/src/lib/serverConfig.js
  • bot-public/src/lib/moderation/guard.js
  • Confirmé que web/ n'est pas suivi par un dépôt git local, donc aucune perte d'historique en le supprimant.
  • Suppression de web/package-lock.json.
  • Plus aucun rapport de sécurité fantôme basé sur des dépendances gelées de mai. npm audit échoue désormais proprement (ENOLOCK, "This command requires an existing lockfile") au lieu d'afficher un faux rapport alarmant — signal clair que bun/bun.lock est l'unique source de vérité pour ce projet.
  • Aucun impact fonctionnel : bun install/bun audit/deploy.sh ne dépendent pas de ce fichier.
  • web/package-lock.json (supprimé)
  • Repris bun audit (source fiable) : 18 vulnérabilités, dont deux réintroduites par le rollback : adm-zip <0.6.0 (high, CVE-2026-39244 — désallocation mémoire non bornée sur une archive ZIP forgée) et sharp <0.35.0 (high, CVE-2026-33327/33328/35590/35591 dans libvips).
  • Vérifié avant d'agir, pour chacune des 2 mises à jour directes concernées :
  • Node.js du serveur = v24.15.0, largement au-dessus du minimum requis par sharp@0.35 (Node >= 20.9.0) → pas de blocage.
  • Code source audité (grep) : web/src/lib/profile-image-sanitize.ts (seul usage direct de sharp) n'utilise aucune des options supprimées/renommées en 0.35 (failOnError, paletteBitDepth, anciennes props sharpen, format.jp2k). Sans risque de casse.
  • adm-zip : les deux seuls usages (web/src/app/api/projects/create/route.ts et .../[slug]/import/route.ts) appellent uniquement new AdmZip(buffer) + getEntries(), jamais extractEntryTo (le seul changement de comportement notable de la 0.6.0 concerne justement cette méthode) → sans risque de casse.
  • Pour les 10 autres vulnérabilités (toutes sur des dépendances transitives, pas de dépendance directe de l'app) : qs, brace-expansion, fast-uri, js-yaml, body-parser, @opentelemetry/core, engine.io, ws, postcss, @babel/core — recherché pour chacune un correctif publié dans la même ligne majeure (donc sans changement d'API), pour éviter de refaire l'erreur du rollback précédent.
  • Piège détecté en cours de route : après avoir forcé sharp via overrides/resolutions, bun audit indiquait encore 1 vulnérabilité car next déclare sa propre dépendance optionnelle interne sharp@^0.34.5 (utilisée par son API d'optimisation d'images), qui installe une copie imbriquée séparée dans node_modules/next/node_modules/sharp — non couverte par un simple bump du sharp racine. Un override explicite ("sharp": "^0.35.3" dans overrides/resolutions) force bun à réutiliser la version patchée partout, y compris pour next.
  • Piège n°2 : après ce changement, un rm -rf node_modules && bun install (pour forcer un état propre) a échoué à mi-chemin — l'environnement shell a un alias bun qui route systématiquement les installs via Socket Firewall (sfw), un proxy de scan de sécurité qui a rencontré une erreur réseau (fetch failed) et interrompu l'installation en cours de route (node_modules incomplet, next absent). Contourné en appelant le binaire réel directement (/root/.bun/bin/bun install, via la variable d'env déjà présente LBXMB_PM_REAL_BUN), qui a terminé l'installation sans erreur.
  • web/package.json :
  • adm-zip ^0.5.18 → ^0.6.0 (fix CVE-2026-39244).
  • sharp ^0.34.5 → ^0.35.3 (fix CVE-2026-33327/33328/35590/35591 dans libvips).
  • Bloc overrides/resolutions étendu pour forcer, sur toute la profondeur de l'arbre (y compris les copies imbriquées comme celle de next), les versions patchées suivantes, toutes dans la même ligne majeure que l'existant (aucun changement d'API attendu) : qs → ^6.15.3, brace-expansion → ^1.1.18, fast-uri → ^3.1.5, js-yaml (nouveau) → ^4.3.1, body-parser (nouveau) → ^2.3.0, @opentelemetry/core (nouveau) → ^2.10.0, engine.io (nouveau) → ^6.6.9, ws (nouveau) → ^8.21.1, postcss (nouveau) → ^8.5.25, @babel/core (nouveau) → ^7.29.7, sharp (nouveau, pour couvrir la copie imbriquée de next) → ^0.35.3.
  • Réinstallation complète et propre (rm -rf node_modules + bun install via le binaire réel, en contournant le wrapper sfw défaillant), pour éliminer toute copie imbriquée obsolète résiduelle.
  • Build + déploiement via deploy.sh.
  • bun audit : 0 vulnérabilité (34 au départ → 18 après le rollback de sécurité → 0 maintenant), sans réintroduire aucune des montées de version majeures risquées annulées à 14:58.
  • Aucune régression observée après déploiement (login/accueil en 200, logs pm2 sans nouvelle erreur liée à sharp/adm-zip/aux paquets patchés).
  • npm audit/package-lock.json à considérer comme non pertinents tant que bun reste le gestionnaire de paquets du projet (fichier obsolète, pourrait être supprimé pour éviter toute confusion future — non fait ici, décision à prendre par l'équipe).
  • web/package.json
  • web/bun.lock
  • Or notre flow (CapActionGate → login/page.tsx) ferme la modale (onOpenChange(false)) immédiatement après un onSolve réussi, ce qui démonte le composant CapWidget/l'élément <cap-widget> dans la foulée → déclenche disconnectedCallback() → dispatch "reset" → notre handleReset dans CapWidget.tsx appelait alors systématiquement onExpireRef.current?.(), qui remonte jusqu'à login/page.tsx et affiche toujours le même message générique "La vérification a échoué ou a expiré.", peu importe que le solve ait réussi.
  • Le token capturé par onSolve avait déjà été utilisé pour lancer handleOAuthLogin → d'où la redirection Discord qui se produit quand même juste après l'affichage (trompeur) de l'erreur.
  • Ce bug était systématique (se produit à 100% des logins réussis via la modale Cap), contrairement au bug d'instrumentation CSP (14:44) qui ne se manifestait que lorsque l'instrumentation anti-bot était sollicitée.
  • web/src/components/cap/CapWidget.tsx : le handler "reset" ignore désormais l'événement si host.isConnected === false, c'est-à-dire si l'élément a déjà été retiré du DOM au moment où l'événement arrive (signature d'un disconnectedCallback()/démontage, pas d'une vraie expiration). Un reset "en direct" (widget encore affiché à l'écran, ex. véritable expiration du token après plusieurs heures) reste bien traité normalement (remet solvedRef à false, déclenche onExpire).
  • Plus de faux message d'erreur après un captcha résolu avec succès sur /login (et les autres écrans utilisant CapActionGate/CapWidget en modale : commencer, verify/[id], etc.).
  • Les vraies expirations (widget resté affiché, token périmé) continuent d'être signalées normalement.
  • web/src/components/cap/CapWidget.tsx
  • | isomorphic-dompurify | 2.36.0 | 3.21.0 |

    | swiper | 12.2.0 | 14.0.7 (+2 majeures) |

    | @socket.io/sticky | 1.0.4 | 2.0.1 |

    | react / react-dom | 19.2.5 | 19.2.8 |

    | react-easy-crop | 5.5.7 | 6.2.3 |

    | adm-zip | 0.5.18 | 0.6.0 |

    | basic-ftp | 5.3.1 | 6.2.0 |

    | typescript | 6.0.3 | 7.0.2 |

    | eslint-config-next | 16.2.4 | 16.2.12 |

    | react-doctor | 0.2.16 | 0.9.3 |

    | @types/node | 25.9.5 | 26.1.2 |

    Symptôme déjà visible avant le rollback : isomorphic-dompurify@3.21.0 (nouveau jsdom) plantait le rendu markdown du forum (Error: Failed to load external module jsdom-...: TypeError: webidl.util.markAsUncloneable is not a function), et typescript@7.0.2 cassait carrément le build (next build refusait de type-checker, d'où l'ajout — temporaire et depuis retiré — d'experimental.useTypeScriptCli dans next.config.js).

    ### Pourquoi c'est dangereux

    ### Changements appliqués (rollback)

    ### Impact

    ### Fichiers

    • redis, bullmq, cookie, @socket.io/sticky, sharp sont des dépendances runtime critiques (sessions/cache, files de jobs, cookies d'auth, sticky sessions Socket.IO en mode cluster PM2, traitement d'images) : des sauts de version majeure changent souvent leurs API sans que le code applicatif soit adapté, avec un risque de plantage silencieux (pas forcément une erreur immédiate au build).
    • Ça a été fait directement sur le checkout de prod, sans passer par un environnement de test (dev-web/ptb-web), et sans figer volontairement les versions dans package.json — un bun install/deploy.sh ultérieur aurait pu re-livrer la même chose.
    • web/package.json : tous les paquets ci-dessus remis à leur version d'avant (celle qui tournait en prod avant cet incident), à l'exception de cap-widget qui reste à jour en 0.1.56 (mise à jour volontaire, voir entrée précédente) et de daisyui/hono/jose (montées mineures dans le range déjà déclaré par package.json, sans risque de breaking change, laissées telles quelles).
    • web/next.config.js : retrait d'experimental.useTypeScriptCli (n'a plus lieu d'être, typescript repasse en ^6.0.3 qui est nativement compatible avec Next.js 16).
    • bun install pour resynchroniser node_modules/bun.lock sur ces versions figées.
    • Nouveau build + déploiement via deploy.sh (pm2 restart web-prod --update-env).
    • Prod repassée sur un jeu de dépendances connu et stable (celui qui tournait avant l'incident), fix Cap conservé.
    • Erreur de rendu markdown forum (jsdom/isomorphic-dompurify) disparue après le rollback (vérifié : plus aucune occurrence dans les logs pm2 après pm2 flush + requête fraîche sur /forum).
    • Recommandation pour la suite : ne jamais lancer bun update --latest directement dans ~/lbxmb.fr/web (prod). Le faire dans dev-web/ ou ptb-web/, tester les fonctionnalités concernées (auth/cookies, files de jobs, upload/images, temps réel Socket.IO), puis ne reporter en prod que les montées de version validées, une par une si besoin.
    • web/package.json
    • web/bun.lock
    • web/next.config.js
  • Conséquence concrète : le calcul PoW du captcha réussit toujours (d'où "cap marche très bien" côté utilisateur), mais l'instrumentation bloquée par la CSP finit par timeout après 20s et le widget déclenche un événement error ("Instrumentation timed out"/"blocked") → notre code (CapActionGate → login/page.tsx) affichait alors toujours le même message générique "La vérification a échoué ou a expiré.", quel que soit le motif réel.
  • Vérifié en confrontant le code source des deux versions npm (cap-widget@0.1.53 vs 0.1.56) : le mécanisme de nonce existe bien dès la 0.1.53, donc le vrai bug était côté intégration lbxmb.fr (nonce jamais fourni), pas une régression du widget — mais une mise à jour du widget reste bénéfique (guards anti-crash supplémentaires sur les continuations async spéculatives, cf. PR amont tiagozip/cap#257).
  • Bonus repéré dans les logs docker logs lbxmb-cap : plusieurs [ERR ...] {"error":{}} suivis à chaque fois d'un redémarrage du conteneur (🧢 Cap running... répété), signe de crashs intermittents côté serveur Cap sur les dernières semaines — corrigés eux aussi par la mise à jour de l'image.
  • web/src/components/cap/CapNonceScript.tsx (nouveau) : composant serveur qui lit le nonce CSP (x-nonce, généré par web/src/proxy.ts) et l'expose au navigateur via window.CAP_CSS_NONCE / window.CAP_SCRIPT_NONCE dans un <script nonce="..."> — même nonce que celui déclaré dans l'en-tête Content-Security-Policy de la requête en cours.
  • web/src/app/layout.tsx : montage de <CapNonceScript /> dans le <body>, avant tout le reste, pour que la variable soit posée avant que le widget Cap (chargé en lazy import("cap-widget") sur les pages qui l'utilisent : login, commencer, verify/[id], etc.) ne l'utilise.
  • web/package.json : cap-widget mis à jour 0.1.53 → 0.1.56 (bun add cap-widget@0.1.56).
  • Cap Standalone : docker pull tiago2/cap:latest (nouvelle image, l'ancienne datait de mai) + docker-compose up -d dans web/cap/ pour recréer le conteneur lbxmb-cap avec l'image à jour. lbxmb-cap-valkey inchangé (déjà à jour, healthy).
  • web/next.config.js : ajout de experimental.useTypeScriptCli: true, nécessaire pour que next build fonctionne avec TypeScript 7.x (package.json épingle typescript: ^7.0.2) — sans ce flag Next.js 16 refuse de type-checker et le build plantait (TypeScript 7.0.2 does not provide the compiler API required by Next.js), bloquant le déploiement de ce correctif.
  • Build + déploiement production via deploy.sh (build Next.js, swap .next-staging, pm2 restart web-prod --update-env). Vérifié après coup : le nonce injecté dans <script>window.CAP_SCRIPT_NONCE=... correspond bien au nonce de l'en-tête Content-Security-Policy de la même requête sur /login.
  • Le captcha Cap sur /login (et les autres pages qui l'utilisent) ne devrait plus afficher de faux message "vérification a échoué" après un captcha pourtant résolu : l'instrumentation anti-bot peut désormais s'exécuter normalement sous notre CSP stricte au lieu de timeout après 20s.
  • Cap Standalone à jour, avec les correctifs de stabilité serveur des ~2 derniers mois (crashs intermittents observés dans les logs avant mise à jour).
  • Widget cap-widget à jour (0.1.56), avec les derniers correctifs anti-crash du composant.
  • Build de prod débloqué durablement (useTypeScriptCli), plus seulement pour ce déploiement.
  • web/src/components/cap/CapNonceScript.tsx (nouveau)
  • web/src/app/layout.tsx
  • web/package.json / web/bun.lock
  • web/next.config.js
  • web/cap/docker-compose.yml (image tiago2/cap:latest re-pull, pas de changement de fichier — conteneur recréé)
  • Debug approfondi avec logging nginx dédié : ajout temporaire d'un log_format cookiedebug (capturant $http_cookie et $sent_http_set_cookie bruts) sur un fichier séparé, pour voir exactement ce que le téléphone envoie/reçoit à chaque requête. Confirmé : le navigateur envoyait deux cookies distincts avec le même nom techaro.lol-anubis-auth (un très ancien + un frais), et même après un fix.html renforcé avec suppression forcée côté serveur (add_header Set-Cookie ... Max-Age=0 sur toutes les combinaisons Domain/Path plausibles, indépendant de tout JS/HttpOnly), le vieux cookie revenait identique à la requête suivante.
  • Résolution réelle : un vidage complet des données du site via le panneau natif de Chrome (icône d'info/cadenas à côté de l'URL → Paramètres du site → "Effacer et réinitialiser") a fonctionné, là où fix.html et le menu classique "Effacer les données de navigation" (qui a une période par défaut, souvent "dernière heure", trop courte pour un cookie vieux de 20h) ne suffisaient pas. Cela confirme que la donnée fautive persistante n'était pas atteignable par nos moyens serveur (Set-Cookie) ni par l'API JS document.cookie/Cache Storage/Service Worker — vraisemblablement un artefact de stockage spécifique au navigateur (ex: cookie à Path différent de /, ou état lié à une ancienne interaction avec /.within.website/) que seule la remise à zéro complète du panneau natif du navigateur peut purger.
  • Anubis mis à jour 1.25.0 → 1.26.2 sur le serveur (bénéficie de tous les correctifs de robustesse du challenge amont, recommandé de garder à jour désormais).
  • Logging de debug temporaire (cookiedebug dans nginx.conf + fichier lbxmb.fr-cookiedebug.log) entièrement retiré une fois le diagnostic terminé.
  • fix.html et ses en-têtes de suppression de cookie sur /etc/nginx/sites-enabled/lbxmb.fr restent en place (utile comme première tentative rapide, sans garantie à 100% dans tous les cas de figure extrêmes).
  • Anubis à jour avec les derniers correctifs de fiabilité du challenge, notamment sur connexions mobiles instables.
  • Cas confirmé résolu pour le signalant.
  • Pour la communauté : si https://lbxmb.fr/fix.html ne suffit pas à débloquer quelqu'un, la procédure de secours fiable à 100% est : appuyer sur l'icône (i) ou le cadenas à côté de l'URL dans Chrome → Paramètres du site (ou "Autorisations du site") → "Effacer et réinitialiser" / "Supprimer les données", PAS le menu générique "Effacer les données de navigation" (qui a une période limitée par défaut).
  • /etc/nginx/nginx.conf (hors dépôt git, config système — retrait du log_format cookiedebug)
  • /etc/nginx/sites-enabled/lbxmb.fr (hors dépôt git, config système — retrait de l'access_log de debug)
  • Binaire système /usr/bin/anubis (1.25.0 → 1.26.2, hors dépôt git)
  • Solution retenue : page de réparation dédiée web/public/fix.html, exemptée d'Anubis (répond toujours en 200 direct, jamais en redirection → ne peut pas re-déclencher le bug qu'elle corrige). Son JS inline désinscrit tous les Service Workers de l'origine + vide le Cache Storage, puis redirige vers /. Comme cette page ne dépend d'aucune redirection ni d'aucun mécanisme de mise à jour incertain, elle fonctionne à coup sûr dès qu'elle est ouverte, même par un navigateur encore bloqué par l'ancien Service Worker.
  • Bug découvert en déployant fix.html : nouvelle 404 alors que le fichier existait bien dans public/. Cause : contrairement à une modification de contenu d'un fichier déjà connu (ex: sw.js, appliquée à chaud), Next.js (serveur custom server.js) ne détecte un fichier tout neuf ajouté dans public/ qu'au redémarrage du process → nécessite un pm2 reload web-prod (zero-downtime, cluster) pour être servi.
  • Second bug découvert : une fois servie, fix.html recevait quand même le header Content-Security-Policy strict généré par web/src/proxy.ts (Next 16, ex-middleware) avec script-src 'nonce-...' 'strict-dynamic' → un script inline sans le bon nonce y est bloqué par le navigateur, ce qui aurait rendu la page de réparation inopérante silencieusement. Corrigé côté nginx avec proxy_hide_header Content-Security-Policy; sur la location dédiée (pas de rebuild nécessaire). Vérifié en direct (port 8080 local + via Cloudflare avec cache-busting, cf-cache-status: DYNAMIC) : header absent, page fonctionnelle.
  • web/public/fix.html (nouveau) : page de réparation, JS inline getRegistrations() → unregister() par worker + caches.keys() → caches.delete(), puis location.replace('/').
  • /etc/nginx/sites-enabled/lbxmb.fr : nouvelle location = /fix.html bypassant Anubis (comme /sw.js), avec proxy_hide_header Content-Security-Policy et Cache-Control: no-store.
  • pm2 reload web-prod (zero-downtime) pour que le nouveau fichier public/fix.html soit reconnu par Next.js.
  • web/public/sw.js : confirmé inchangé (version finale du fix précédent, pas le kill-switch expérimental — celui-ci n'a jamais été gardé en prod au-delà du test de 90s).
  • Un visiteur bloqué dans la boucle infinie peut désormais ouvrir manuellement https://lbxmb.fr/fix.html une seule fois : la page se charge instantanément (jamais de challenge Anubis dessus), nettoie le Service Worker cassé en quelques centaines de ms, puis renvoie automatiquement vers l'accueil — qui charge alors normalement et réinstalle un Service Worker propre. Beaucoup plus simple et fiable qu'expliquer la procédure de vidage manuel des données du navigateur.
  • N'affecte pas la protection anti-bot du reste du site (seule cette page précise bypass Anubis).
  • web/public/fix.html (nouveau)
  • /etc/nginx/sites-enabled/lbxmb.fr (hors dépôt git, config système)
  • Le vrai bug est côté navigateur : web/public/sw.js (Service Worker PWA, scope /) interceptait toutes les requêtes GET, y compris les navigations complètes (event.respondWith(fetch(event.request))).
  • Anubis valide le challenge via une redirection HTTP 302 sur /.within.website/x/cmd/anubis/api/pass-challenge (pose du cookie d'auth).
  • Une requête de navigation refetchée depuis un Service Worker a un redirect forcé à "manual" par la spec Fetch → la réponse 302 devient une réponse opaqueredirect. Le comportement de certains navigateurs face à ce cas est incohérent → la navigation reste bloquée indéfiniment (d'où "certaines personnes" uniquement).
  • Ce Service Worker ne fait par ailleurs aucun cache (pas de caches.match/put), donc intercepter les navigations n'apportait aucun bénéfice, que du risque.
  • Bug additionnel découvert en creusant : /sw.js et /manifest.json n'étaient pas exemptés d'Anubis côté nginx (contrairement à /_next/static, /uploads/, etc.). navigator.serviceWorker.register('/sw.js', { updateViaCache: 'none' }) force un fetch réseau à chaque vérification de mise à jour ; si le cookie Anubis est absent/expiré à ce moment-là, Anubis renvoyait la page HTML du challenge à la place du script JS (mauvais Content-Type), cassant l'installation/mise à jour du Service Worker.
  • web/public/sw.js : le fetch handler ignore désormais les requêtes de navigation (event.request.mode === 'navigate') et tout le namespace Anubis (/.within.website/) → le navigateur gère nativement ces requêtes, plus d'interférence avec la redirection de validation du challenge.
  • /etc/nginx/sites-enabled/lbxmb.fr : ajout de deux location dédiées (= /sw.js, = /manifest.json) qui bypassent Anubis et proxient directement vers web_cluster, comme /_next/static. Config validée (nginx -t) puis rechargée (systemctl reload nginx).
  • Le Service Worker ne peut plus jamais intercepter/casser la redirection de validation du challenge Anubis → fin du chargement infini pour les nouveaux visiteurs/nouvelles installations du Service Worker.
  • /sw.js et /manifest.json toujours servis correctement (JS/JSON, jamais la page de challenge), même sans cookie Anubis valide.
  • Aucun impact sur la protection anti-bot elle-même : / et le reste du site continuent de passer par Anubis normalement.
  • Les visiteurs ayant déjà un Service Worker cassé en cache devront un vidage ponctuel des données du site (une seule fois) pour recevoir la version corrigée ; les nouveaux visiteurs ne seront plus affectés.
  • web/public/sw.js
  • /etc/nginx/sites-enabled/lbxmb.fr (hors dépôt git, config système)
  • bot-public/src/handlers/verification/unverifiedKickScheduler.js
  • bot-public/src/events/guild/guildMemberAdd.js
  • bot-public/src/handlers/roles/autoRoleEngine.js
  • Règlement lisible sur https://lbxmb.fr/legal/reglement
  • Les membres déjà passés : re-sauver les prefs sur /roles pour réappliquer les accès
  • bot-site/src/lib/discordRest.js, bot-site/src/lib/commencerCategories.js, bot-site/src/lib/commencerChannelAccess.js
  • bot-site/src/config.js, bot-site/src/index.js
  • web/src/lib/commencer-categories.ts, web/src/app/api/roles/route.ts
  • web/src/app/legal/reglement/page.tsx
  • bot-public/src/handlers/config/panelsSecurity.js
  • bot-public/src/handlers/config/routerSecurity.js
  • bot-public/data/serveur/1232966743241130005.json
  • bot-public/src/config.js (dotenv ignore DISCORD_TOKEN="" injecté par PM2/shell)
  • vidéo 1310212490159853631
  • web/src/app/roles/page.tsx, web/src/app/api/roles/route.ts
  • web/src/lib/notif-roles.ts, web/src/lib/discord-bot-site.ts
  • web/lib/allowed-isps.cjs
  • bot-public/src/lib/notifChannelDm.js
  • bot-public/src/events/message/messageCreate.js
  • bot-public/src/handlers/verification/verificationPanel.js
  • web/lib/verify-oauth-callback.cjs
  • web/src/lib/verify-oauth-callback-logic.ts
  • bot-public/src/handlers/verification/verificationPanel.js
  • bot-public/src/events/guild/guildMemberAdd.js
  • bot-site/src/lib/commencerChannelAccess.js
  • bot-public/src/lib/verifyAdminInbox.js
  • 8. Deploy : build → .next-staging + pm2 restart web-prod

    ### Impact

    Site 200 ; vérif doit re-accepter les 3 cases ; guides README visibles ; permissions staff se rafraîchissent ; moins d’erreurs DECIMAL à l’onboarding.

    ### Fichiers

    • web/src/lib/{legal-accept,users-lookup,auth-helpers}.ts, api/{commencer,auth/me}, guides/*, Hero, Cap*, Footer, mentions, rgpd redirect, messages fr/en, DashboardContext, QueryProvider, use-auth-me, chunked-upload/server.ts
    • /etc/anubis/lbxmb.env
  • Retrait du hardcode upload.lbxmb.fr dans upload-api.ts / cloud-upload.ts (même origine + chunks).
  • Fichiers ≤ 95 MiB : comportement inchangé (1 POST).
  • Fichiers > 95 MiB : découpés automatiquement, passent le proxy CF, réassemblés côté serveur avant écriture / antivirus.
  • Limites métier inchangées (5 Mo photo, 2 Go cloud, etc.) appliquées sur la taille totale.
  • web/src/lib/chunked-upload/*, web/src/lib/chunked-upload-client.ts
  • web/src/app/api/uploads/chunks/**
  • Routes API upload (cloud, resources, staff-hub, shop, guides, tickets, profil, chat, forum, projects, vendor, shared-games, dashboard resources, staging admin…)
  • Clients : cloud-upload.ts, upload-api.ts, ressources/ajouter, chat, staff-hub, forum, projects, MessageBell, Shop, profil, etc.
  • docs/RECAP-TRAVAIL-COMMUNAUTE-2026-04.md
  • infra/cloudflared/config.example.yml
  • Page /compte-desactive + API contestation 1 seule fois
  • Guard client redirect si session OAuth sur compte désactivé
  • Login JWT : code ACCOUNT_DISABLED + lien contestation
  • Page /verify/[id] : liste opérateurs + formulaire « Mon opérateur n’est pas autorisé »
  • Admin /dashboard/verification-isp : approuver/refuser demandes + extras manuels
  • /commencer : même whitelist mondiale ; plus de blocage mobile-only
  • ~999 kicks réussis (+ 1 résiduel nettoyé)
  • Tâche closed, ~198 membres restants (keepers + bots/owners)
  • Quelques échecs 429 Discord pendant le pass (rattrapés / absents ensuite)
  • Fix TS Record<string, string> + redeploy web prod
  • Nouveau container « Menu vocal » (accent coral) + image légende (canvas) des 8 icônes.
  • ✏️ nom / statut vocal / bitrate · 👥 limite · 🔒/🔓 masquer · 🛡️ perms (modal checkboxes) · ➕ autoriser · ➖ retirer · 📨 transfert · 👑 claim si proprio absent.
  • Toggles via guild.setIncidentActions (max 24 h) : pause invitations + blocage MP entre inconnus.
  • Texte explicatif : amis Discord / admins peuvent toujours s'écrire.
  • bot-site/src/lib/regularization/activity.js, runner.js, message.js, config.js, .env
  • bot-public/src/lib/memberActivity.js
  • bot-public/src/events/guild/presenceUpdate.js, guildMemberAdd.js
  • bot-public/src/events/message/messageReactionAdd.js
  • bot-public/src/events/interaction/interactionCreate.js
  • docs/RECAP-TRAVAIL-COMMUNAUTE-2026-04.md
  • buildDownloadVariantsFromTelechargements : liste plate par fichier configuré, sans inférence OS.
  • featured-home : requête discord_id + fallback CDN ; Hero deux avatars chevauchés.
  • UX changelog, fiche ressource, connexion Discord et téléchargements alignées sur la config réelle.
  • Accueil affiche interverti + Default.xex.
  • web/src/app/changelogs/page.tsx
  • web/src/app/ressources/[slug]/ResourceDetailClient.tsx
  • web/src/app/api/auth/discord/user-install/route.ts
  • web/src/app/login/page.tsx, web/src/components/auth/LoginButtons.tsx
  • web/src/lib/download-variants-tree.ts
  • web/src/app/api/users/featured-home/route.ts, web/src/components/home/Hero.tsx
  • docs/RECAP-TRAVAIL-COMMUNAUTE-2026-04.md
  • Futurs ajouts fichier ne seront plus classés « Site » par accident.
  • uploads/Structure/Xbox One/Tools/Xb Homebrew Vault/structure.json
  • web/src/lib/is-site-resource.ts
  • web/src/lib/resource-add-from-form.ts
  • web/src/app/ressources/[slug]/ResourceDetailClient.tsx
  • web/src/app/ressources/page.tsx
  • web/src/app/ressources/ajouter/page.tsx
  • docs/RECAP-TRAVAIL-COMMUNAUTE-2026-04.md
  • Fichiers voice-*.webm rendus en <audio controls> (plus en <video>).
  • Normalisation API : membre, action, lieu (salon / type).
  • Libellés de filtre traduits (Modération, Vocal…).
  • Offset sous le Header fixe ; scroll interne ; bottom nav masquée sur /cloud.
  • Deux avatars côte à côte : 674329017339346955 puis 1139951514694193323.
  • API repo-info renvoie les assets release ; pré-remplissage auto des téléchargements (URLs).
  • web/src/app/api/resources/structure/route.ts
  • web/src/components/boutique/ProductCard.tsx, profile/Shop.tsx, app/boutique/page.tsx
  • web/src/lib/auth.ts, AssociatedAccounts.tsx, app/profil/page.tsx
  • web/src/lib/staff-chat-media.ts, StaffHubChannelPanel.tsx
  • web/src/lib/normalize-discord-log.ts, StaffHubDiscordLogsPanel.tsx, discord-logs/route.ts
  • web/src/app/cloud/page.tsx, AppScrollShell.tsx, MobileBottomNav.tsx
  • web/src/components/home/Hero.tsx, api/users/featured-home/route.ts
  • web/src/app/api/github/repo-info/route.ts, ressources/ajouter/page.tsx
  • docs/RECAP-TRAVAIL-COMMUNAUTE-2026-04.md
  • bot-public/src/events/guild/voiceStateUpdate.js
  • bot-public/src/events/guild/presenceUpdate.js
  • bot-public/src/commands/util/sondage.js
  • bot-site/src/lib/regularization/activity.js, message.js, runner.js
  • bot-site/src/lib/discordRest.js, config.js, index.js
  • bot-site/.env.example
  • docs/RECAP-TRAVAIL-COMMUNAUTE-2026-04.md
  • Redémarrer bot-public (tracking) et bot-site (scheduler).
  • Les participations aux sondages comptent via les votes du commande /sondage uniquement.
  • User Install (global).
  • Interface multi-containers avec commandes cliquables </cmd:id> par catégorie ; réponse visible.
  • Contexte : affichage de toutes les sections d'un coup = trop d'infos.
  • Changement : une seule catégorie visible (Utilitaires, Musique, Utilisateur, Modération, Administration) ; titres # = options du StringSelectMenu ; commandes cliquables conservées.
  • bot-public/src/handlers/config/panelsAdmin.js, routerAdmin.js, adminCustomModals.js, router.js
  • bot-public/src/lib/commandSync.js, guildWelcome.js, contestInvite.js
  • bot-public/src/commands/util/invite-bot.js, help.js
  • bot-public/src/commands/moderation/base64.js
  • bot-public/src/handlers/report/reportHandler.js
  • bot-public/src/handlers/moderation/contestationHandler.js
  • bot-public/src/events/guild/guildCreate.js
  • bot-public/src/events/interaction/interactionCreate.js
  • docs/RECAP-TRAVAIL-COMMUNAUTE-2026-04.md
  • À la connexion/liaison Discord : application automatique des blocages pour les IDs déjà blacklistés.
  • web/src/lib/discord-oauth.ts, web/src/lib/discord-relationships.ts
  • web/src/lib/auth.ts
  • web/src/app/api/profil/oauth-providers/prepare-link/route.ts
  • web/src/app/api/auth/callback/discord/link/route.ts
  • web/src/app/api/verify/discord/authorize/route.ts
  • web/src/app/api/internal/discord/blacklist-relationships/route.ts
  • web/src/app/discord/bot/page.tsx
  • bot-public/src/lib/siteBlacklistRelationships.js
  • bot-public/src/commands/owner/blacklist.js
  • bot-public/src/lib/moderation/sanctionNotify.js
  • bot-public/scripts/print-install-links.js
  • docs/RECAP-TRAVAIL-COMMUNAUTE-2026-04.md
  • Les utilisateurs existants devront ré-autoriser Discord pour obtenir relationships.write.
  • Propagation blocage active dès qu'un compte site a autorisé l'app avec le nouveau scope.
  • docs/RECAP-TRAVAIL-COMMUNAUTE-2026-04.md
  • bot-public redémarré ; commandes utilisables en User Install sur un serveur.
  • Contexte : garanties et options complémentaires saisies en admin mais absentes sur la fiche ; options avec surcoût non reflétées au checkout.
  • Changements : affichage garanties, sélecteur d’options avec price_delta, prix dynamique, envoi selected_options au checkout Stripe.
  • Fichiers : web/src/app/boutique/[id]/page.tsx
  • Contexte : afficher le profil Discord 1139951514694193323 (Default.xex) dans le hero.
  • Changements : API /api/users/featured-home, hook useHomeFeaturedProfile, Hero simplifié (un seul avatar).
  • Fichiers : web/src/app/api/users/featured-home/route.ts, web/src/hooks/use-home-queries.ts, web/src/components/home/Hero.tsx
  • Contexte : date « connecté le » = liaison OAuth (ex. 3 juillet) ; doublons de providers ; cards peu lisibles.
  • Changements : table user_auth_log, journalisation à la session OAuth, API providers limitée au better_auth_user_id, affichage « dernière connexion » par provider, cards refaites.
  • Fichiers : web/src/lib/auth-login-log.ts, web/src/lib/auth.ts, web/src/app/api/user/record-auth-login/route.ts, web/src/app/api/profil/oauth-providers/route.ts, web/src/components/profile/AssociatedAccounts.tsx, web/src/components/auth/LoginButtons.tsx, web/src/app/login/page.tsx, web/src/hooks/use-misc-queries.ts
  • Contexte : menu notifications sous la navbar desktop ; barre logo LBXMB visible avec menu mobile ouvert.
  • Changements : z-[10050] sur dropdown notifications ; header masqué (max-md:hidden) quand le sheet nav mobile est ouvert.
  • Fichiers : web/src/components/notifications/NotificationBell.tsx, web/src/components/layout/Header.tsx
  • Contexte : icône produit mal placée sur mobile.
  • Changements : ProductCard en layout row sur mobile (logo à gauche, infos à droite).
  • Fichiers : web/src/app/boutique/page.tsx
  • Contexte : demande partenariat = titre/description libres insuffisants.
  • Changements : formulaire structuré (nom, description, icône URL/fichier, site, Discord, YouTube, Twitch, TikTok, conditions) ; payload fields JSON + description markdown générée.
  • Fichiers : web/src/components/support/TicketsManager.tsx
  • Build web OK ; web-prod redémarré.
  • Impact : admins serveur peuvent créer /nom renvoyant un message public ou éphémère ; sync auto après création.
  • Fichiers : panelsAdmin.js, routerAdmin.js, router.js, adminCustomModals.js, customCommands.js, commandSync.js, interactionCreate.js
  • Contexte : chaque ressource ajoutée doit créer un fil forum Discord (titre = nom, contenu = lien).
  • Changements : mapping console → salon (data/discord-resource-forum-channels.json), endpoint POST /forum/resource-post sur bot-site, appel direct depuis resources/add, file site_new_resource traitée par bot-public. Script temporaire exécuté puis supprimé : 194/196 ressources publiées (2 ressources console « Sites » sans salon mappé).
  • Impact : nouvelles ressources → fil forum automatique ; backlog existant synchronisé.
  • Fichiers : bot-site/src/index.js, bot-site/src/lib/discordRest.js, bot-site/src/lib/resourceForumChannels.js, web/src/lib/discord-bot-site.ts, web/src/lib/discord-resource-forum.ts, web/src/app/api/resources/add/route.ts, bot-public/src/lib/siteResourceForum.js, webVerificationQueue.js, data/discord-resource-forum-channels.json
  • Contexte : embeds OG trop enrichis (méta Discord, footer auteur).
  • Changements : title = nom ressource, description = description brute sans markdown, image OG = logo (icône) de la ressource.
  • Impact : aperçus Discord/réseaux plus simples et fidèles au contenu.
  • Fichiers : web/src/app/ressources/[slug]/layout.tsx, web/src/lib/og-lbxmb.ts
  • Réinstall : https://discord.com/oauth2/authorize?client_id=1431308308505039069&integration_type=1&scope=applications.commands
  • bot-public/src/commands/util/install.js
  • bot-public/src/lib/commandSync.js
  • bot-public/src/events/interaction/interactionCreate.js
  • bot-public/src/commands/util/help.js
  • bot-public/docs/USER_INSTALL.md
  • docs/RECAP-TRAVAIL-COMMUNAUTE-2026-04.md
  • USER_INSTALL.md : section mobile + tableau User vs serveur.
  • Commandes globales rafraîchies (23).
  • Utilisateurs invitant en 0 perm comprennent pourquoi la traduction ne marche pas ; lien reco disponible.
  • bot-public/src/deploy-commands.js
  • bot-public/src/commands/util/invite-bot.js
  • bot-public/src/lib/botInvite.js
  • bot-public/scripts/print-install-links.js
  • bot-public/docs/USER_INSTALL.md
  • docs/RECAP-TRAVAIL-COMMUNAUTE-2026-04.md
  • bot-public/src/commands/util/help.js
  • bot-public/src/events/interaction/interactionCreate.js
  • bot-public/scripts/print-install-links.js
  • docs/RECAP-TRAVAIL-COMMUNAUTE-2026-04.md
  • bot-public/src/commands/util/rpc.js
  • bot-public/src/lib/{userRpc.js,rpcPresence.js}
  • bot-public/scripts/rpc-local-bridge.js
  • web/src/app/api/rpc/bridge/route.ts
  • docs/RECAP-TRAVAIL-COMMUNAUTE-2026-04.md
  • Dépendance discord-rpc ajoutée.
  • Configuration Rich Presence via /rpc ; application réelle sur le profil via client Discord (RPC IPC / pont local).
  • L'OAuth site seul ne pousse pas la présence à distance : le pont local ou Discord sur la même machine est requis.
  • bot-public/src/commands/util/rpc.js
  • bot-public/src/lib/{userRpc.js,rpcPresence.js,internalHttpServer.js,commandSync.js}
  • bot-public/src/events/interaction/interactionCreate.js
  • bot-public/src/commands/util/help.js
  • bot-public/src/lib/moderation/guard.js
  • bot-public/package.json
  • docs/RECAP-TRAVAIL-COMMUNAUTE-2026-04.md
  • Changement : clés i18n FR/EN complétées ; labels boutons permissions, modales, messages de confirmation.
  • Fichiers : bot-public/src/handlers/tempVoice/controlPanel.js
  • Contexte : emojis en tête des options → erreurs API ; config illimitée mais menu Discord max 25.
  • Changements : helper discordEmoji.js ; pagination éditeur (seloptpage) ; avertissement à la publication si >25 options actives.
  • Fichiers : bot-public/src/lib/discordEmoji.js, panelsRoles.js, routerRoles.js, roleSelector.js
  • Contexte : rôles, salons, URLs traduits ; placeholder LBXMB EMOJI au lieu des vrais emojis.
  • Changement : masquage avant traduction (custom emoji, mentions, URLs, unicode) puis restauration après.
  • Fichiers : bot-public/src/lib/libretranslate.js
  • Contexte : piège anti-scam avec whitelist staff sur salons dédiés.
  • Changement : config /config → Sécurité → Attrape-scam (salons, rôles/users autorisés, suppression messages 1h) ; runtime ban → unban + DM avec lien d'invite.
  • Fichiers : antiRaidModules.js, securityConfig.js, panelsSecurity.js, routerSecurity.js, antiRaidRuntime.js, messageCreate.js
  • Contexte : anti-webhook, anti-bot, anti-thread, anti-join, anti-name, anti-rôle/salon, anti-réaction/emojis/stickers/url/mot avec bypass.
  • Changement : 12 modules configurables (domaines autorisés pour anti-URL, mots pour anti-word) ; events guild + message/reaction.
  • Fichiers : antiRaidModules.js, antiRaidRuntime.js, panelsSecurity.js, routerSecurity.js, securityModals.js, events/guild/ar*.js, index.js (intent GuildModeration)
  • Contexte : pas d'option miniature / grande image sur le container publié.
  • Changement : champs URL dans modal embed ; ThumbnailBuilder + MediaGalleryBuilder à la publication ; aperçu URLs dans l'éditeur.
  • Fichiers : roleModals.js, routerRoles.js, panelsRoles.js, roleSelector.js
  • pm2 restart bot-public
  • Fichiers : panelsSecurity.js, routerSecurity.js
  • Changement : délégation musique/record si bot principal occupé (DISCORD_SECONDARY_TOKEN).
  • Fichiers : secondaryBot.js, index.js, musicManager.js, musicSlashHelpers.js, voiceRecording.js, recordHandler.js
  • Changement : modal 4 champs ; validation rôle ; emojis invalides ignorés.
  • Fichiers : roleModals.js, routerRoles.js, panelsRoles.js
  • pm2 restart bot-public --update-env
  • Changement : intégration User Install + contextes DM/serveur ; option serveur (ID) pour icône/bannière hors serveur.
  • Fichiers : commands/util/pickup.js, commandSync.js
  • Changement : nouvelles commandes en Container V2 (avatar, bannière, badges, stats serveur…) ; User Install ; serverinfo accepte un ID serveur en DM.
  • Fichiers : commands/util/userinfo.js, commands/util/serverinfo.js, guard.js, help.js
  • node src/deploy-commands.js (21 commandes globales)
  • pm2 restart bot-public --update-env
  • Fichiers : commands/util/serverinfo.js
  • Cause : emoji custom mal formé (<:xboxseries:123 sans >) rejeté par l'API Discord.
  • Changement : validation stricte des emojis ; seloptpick sans deferUpdate.
  • Fichiers : discordEmoji.js, routerRoles.js
  • Changement : type Réactions (menu / boutons / réactions) ; emoji obligatoire ; modal après choix du rôle ; handlers messageReactionAdd / messageReactionRemove.
  • Fichiers : roleSelector.js, panelsRoles.js, routerRoles.js, roleModals.js, roleConfig.js, events réactions
  • Changement : option Affichage : Container V2 ou embed classique (display_mode).
  • Fichiers : roleSelector.js, panelsRoles.js, routerRoles.js, roleConfig.js
  • pm2 restart bot-public --update-env
  • Contexte : texte LB'XMB.FR superposé au panneau ; menu trop large ; entrée nav.domains affichée en prod build.
  • Changements :
  • Mobile : logo seul (texte masqué)
  • Panneau navigation : w-[min(82vw,17rem)] au lieu de 22rem
  • Suppression entrée / couleurs domains résiduelles dans Header
  • Fichiers : dev-web/src/components/layout/Header.tsx
  • Contexte : OAuth Discord → retour /login sans session.
  • Cause : PM2 injectait un DISCORD_CLIENT_SECRET obsolète (invalid_client dans les logs) au lieu de .env.local.
  • Changement : redémarrage web-dev sans variables Discord PM2 (lecture .env.local).
  • Fichiers : process PM2 web-dev (pas de diff code)
  • Contexte : avatars Interverti / LoupBlanke obsolètes dans la section « par ».
  • Changement : API publique GET /api/home/owners (Discord IDs 674329017339346955, 1139951514694193323) + Hero utilise cette source avec fallback CDN Discord.
  • Fichiers : dev-web/src/app/api/home/owners/route.ts, dev-web/src/hooks/use-home-queries.ts, dev-web/src/components/home/Hero.tsx, dev-web/src/proxy.ts
  • Contexte : carré noir gênant à l'ouverture de la recherche.
  • Changement : overlay allégé (bg-black/25), fond sheet bg-zinc-950/98, hauteur auto.
  • Fichiers : dev-web/src/components/dashboard/DashboardHeader.tsx
  • npm run build dans dev-web/ → copie .next → .next-staging
  • pm2 restart bot-public
  • pm2 delete web-dev + pm2 start server.js --name web-dev (PORT 25582)
  • /opt/geyser-standalone/config.yml, Geyser.jar, key.pem (hôte)
  • Conteneur Docker geyser-bedrock
  • Plugin Geyser config dans serveur Pterodactyl 257fc463
  • Changements :
  • Module guild_stats : hub + éditeur dans /config → Système automatique → Statistiques serveur
  • Variables : {member.count}, {bot.count}, {member.total}, {role.member.count}, {role.member.count:ID}, {server.name}
  • Scheduler toutes les 10 min + refresh au join/leave
  • Bouton « Appliquer maintenant » par règle
  • Impact : ex. template LBCS {role.member.count} ou {bot.count} / {member.count} sur salon vocal/textuel ou nom serveur.
  • Fichiers : guildStatsConfig.js, guildStatsEngine.js, guildStatsScheduler.js, panelsGuildStats.js, routerCommunity.js, communityModals.js, serverConfig.js, placeholders.js, ready.js, guildMemberAdd.js, guildMemberRemove.js, panelsV2.js
  • Contexte : panneau config dépassait la limite de composants V2 → erreurs d'interaction.
  • Changements :
  • Liste des options remplacée par un menu déroulant seloptpick
  • Publication boutons : jusqu'à 25 options sur plusieurs rangées (5 par rangée)
  • Impact : édition et publication OK avec 6+ rôles.
  • Fichiers : panelsRoles.js, routerRoles.js, roleSelector.js
  • node src/deploy-commands.js
  • pm2 restart bot-public --update-env
  • UI : rôles interdits, whitelist autorisés, @everyone (= id du serveur).
  • Overwrites harmonisés création + reset panneau.
  • Registre PLACEHOLDER_REGISTRY + affichage décrit dans bienvenue, message, vocaux, pseudos.
  • placeholders.js, tempVoiceConfig.js, tempVoiceHandler.js, controlPanel.js
  • welcomeSender.js, guildMemberAdd.js, guildMemberRemove.js
  • roleConfig.js, autoRoleEngine.js, fieldEditV2.js
  • panelsV2.js, panelsRoles.js, routerRoles.js, panelsCommunity.js, routerCommunity.js, router.js, panelsNicks.js
  • pm2 restart bot-public --update-env
  • Helpers partagés musicSlashHelpers.js ; /music (panneau boutons) conservé.
  • 19 commandes globales déployées (Discord peut mettre ~1 h à propager, souvent quelques minutes).
  • Forcer la sync : retirer/réinviter le bot ou attendre le cache Discord.
  • bot-public/src/commands/util/radio.js, play.js, skip.js, queue.js, pause.js, resume.js, stop.js, volume.js, playlist.js
  • bot-public/src/lib/music/musicSlashHelpers.js, musicManager.js
  • bot-public/src/lib/commandSync.js
  • bot-public/src/events/interaction/interactionCreate.js
  • node src/deploy-commands.js (19 commandes globales)
  • pm2 restart bot-public --update-env
  • Helpers partagés musicSlashHelpers.js ; /music (panneau boutons) conservé.
  • 19 commandes globales déployées (Discord peut mettre ~1 h à propager, souvent quelques minutes).
  • Forcer la sync : retirer/réinviter le bot ou attendre le cache Discord.
  • bot-public/src/commands/util/radio.js, play.js, skip.js, queue.js, pause.js, resume.js, stop.js, volume.js, playlist.js
  • bot-public/src/lib/music/musicSlashHelpers.js, musicManager.js
  • bot-public/src/lib/commandSync.js
  • bot-public/src/events/interaction/interactionCreate.js
  • node src/deploy-commands.js (19 commandes globales)
  • pm2 restart bot-public --update-env
  • Modal /config rôles temporaires : saisie texte + champ duration_text enregistré.
  • tempRoleStore : durée minimale 1 seconde (minutes fractionnaires supportées).
  • Durées lisibles dans les panneaux (formatDurationMinutes).
  • Rôles temporaires expirables à la seconde près.
  • bot-public/src/lib/durationParse.js
  • bot-public/src/handlers/config/roleModals.js, routerRoles.js, panelsRoles.js
  • bot-public/src/lib/roleConfig.js, tempRoleStore.js, handlers/roles/autoRoleEngine.js
  • Doublons de variables dans le container /config.
  • Manquaient {invite.link} et {invite.display.name}.
  • placeholders.js : liste unique WELCOME_VARIABLE_HELP sans doublons.
  • Nouveaux placeholders {invite.link} et {invite.display.name}.
  • inviteTracker enrichi (lien, nom salon / inviteur).
  • Correction affichage redondant embed/simple dans panelsV2.js.
  • bot-public/src/lib/placeholders.js
  • bot-public/src/handlers/invites/inviteTracker.js
  • bot-public/src/events/guild/guildMemberAdd.js
  • bot-public/src/handlers/welcome/welcomeSender.js
  • bot-public/src/handlers/config/panelsV2.js
  • Utilisateurs blacklistés pas toujours bannis des serveurs ; MP incomplet.
  • blacklistEnforce.js : guild.bans.create() même si non-membre, vérif hiérarchie bannable, logs détaillés.
  • enforceAllBlacklistBans() au démarrage du bot (rétroactif).
  • MP blacklist : modérateur, raison, durée, résumé bans serveurs.
  • Signalements validés → ban tous serveurs aussi.
  • bot-public/src/lib/blacklistEnforce.js, blacklist.js
  • bot-public/src/lib/moderation/sanctionNotify.js
  • bot-public/src/commands/owner/bl.js
  • bot-public/src/handlers/report/reportHandler.js
  • bot-public/src/events/client/ready.js
  • /radio play station: avec autocomplete (NRJ, Skyrock, RTL, France Inter, etc.).
  • /radio stop pour couper le flux.
  • Lecture via ffmpeg + @discordjs/voice ; arrête la musique si active.
  • bot-public/src/commands/util/radio.js
  • bot-public/src/lib/music/radioStations.js, radioManager.js
  • bot-public/src/events/interaction/interactionCreate.js
  • node src/deploy-commands.js
  • pm2 restart bot-public --update-env
  • Le site/outils peuvent ping le bot et forcer le flush vérif.
  • Port non exposé sur Internet (localhost uniquement — sécurité).
  • Les panneaux /config Discord restent côté Discord (pas besoin d'ouvrir le port au public).
  • bot-public/src/lib/internalHttpServer.js
  • bot-public/src/handlers/verification/webVerificationQueue.js
  • bot-public/src/events/client/ready.js
  • bot-public/.env, bot-public/.env.example
  • ecosystem.config.js
  • pm2 restart bot-public --update-env
  • Test : curl http://127.0.0.1:25591/health
  • #### Changements

    ### 8. Tickets fermés masqués en messagerie

    #### Changements

    #### Fichiers touchés

    ### 9–11. Boutique

    #### Changements

    #### Fichiers touchés

    #### Déploiement

    • IP toujours incorrecte après correctifs précédents (0.0.0.0 / vide).
    • dev.lbxmb.fr utilisait encore $proxy_add_x_forwarded_for (chaîne IP corrompue).
    • client-ip.cjs / client-ip.ts : support header Forwarded (RFC 7239), valeurs header en tableau, pas de fallback 0.0.0.0.
    • verify-oauth-callback.cjs : retour unknown si IP introuvable ; log enrichi (forwarded).
    • nginx dev : bypass /api/verify/ + X-Forwarded-For $real_client_ip (aligné prod).
    • Nouvelle vérif OAuth doit enregistrer l'IP Cloudflare réelle si headers présents.
    • web/lib/client-ip.cjs, web/src/lib/client-ip.ts, web/lib/verify-oauth-callback.cjs
    • /etc/nginx/sites-available/lbxmb.fr (bloc dev.lbxmb.fr)
    • sync dev-web/
    • Nouveau bot-public/src/lib/blacklistEnforce.js : guild.members.ban() sur chaque guild (même si absent).
    • Raison ban : LB'XMB — Blacklist globale : {raison}.
    • /bl add affiche le résumé des bannissements dans l'embed.
    • bot-public/src/lib/blacklistEnforce.js, bot-public/src/commands/owner/bl.js
    • Copie /root/lbxmb.fr/lbxmb.png → web/public/, dev-web/public/, web/src/app/icon.png.
    • presentation/page.tsx : /images/logo-lbxmb.png → /lbxmb.png.
    • DevAccessGuard : whitelist vide → tout utilisateur connecté redirigé vers lbxmb.fr.
    • Whitelist vide = accès dev ouvert (restriction uniquement si DEV_ALLOWED_DISCORD_IDS renseigné).
    • web/src/components/dev/DevAccessGuard.tsx (+ sync dev-web)
    • backdrop-blur uniquement au scroll ou mode non-transparent ; en haut + transparent = aucun flou.
    • web/src/components/layout/Header.tsx
    • Lien « Domaines » retiré de la navbar.
    • Section « Nos domaines » dans le footer (liste LBXMB_OFFICIAL_DOMAINS).
    • /domaines redirige vers /.
    • Header.tsx, Footer.tsx, domaines/page.tsx, messages/fr.json, messages/en.json
    • ApplicationsLauncher : z-[10050] sur le popover.
    • MobileBottomNav : hauteur réduite (h-14), icônes 18px, labels 9px.
    • Sheet mobile nav : items plus compacts (min-h-[44px], text-sm).
    • Filtre closed / resolved dans fetchTickets et buildUnifiedConversationList.
    • MessageBell.tsx, unified-list.ts
    • Cards verticales style Amazon (image carrée pleine largeur, texte en dessous).
    • Page détail : bouton « Ajouter au panier » (addToCart).
    • Bouton Profil vendeur aligné sur le style Contact.
    • boutique/page.tsx, boutique/[id]/page.tsx
    • pm2 restart bot-public
    • cd web && bun run deploy + deploy-web-dev.sh
  • bot-site/src/index.js, bot-site/src/lib/nick.js
  • web/src/lib/discord-bot-site.ts, auth.ts, auth-helpers.ts, app/api/profil/route.ts
  • Le champ d'édition profil n'impose plus toLowerCase() ; conserve la casse via sanitizePseudo.
  • web/src/components/profile/ProfileEditSection.tsx
  • Commande renommée /stats (menu interactif conservé + classement serveurs).
  • Panneau /config → Statistiques vocal : règles mute/sourd/seul, classement serveur/inter-serveurs, tag 4 car., réinitialisation stats.
  • Règles appliquées dans voiceStateUpdate via voiceTimeConfig.
  • Par défaut : classement serveur ON, inter-serveurs OFF, règles OFF.
  • Message si inter-serveurs désactivé lors d'une vue globale.
  • bot-public/src/commands/util/stats.js (remplace voctime.js)
  • bot-public/src/handlers/voiceTime/statsHandler.js
  • bot-public/src/lib/voiceTimeConfig.js, voiceTime.js, serverConfig.js
  • bot-public/src/handlers/config/panelsVoiceStats.js, routerCommunity.js, panelsV2.js
  • bot-public/src/events/guild/voiceStateUpdate.js
  • node src/deploy-commands.js + pm2 restart bot-public bot-site + pm2 restart web-prod --update-env
  • Migration config : fusion des entrées manquantes dans admin.commands / admin.permissions, suppression de l'entrée legacy voctime.
  • bot-public/src/lib/commandSync.js, serverConfig.js, panelsAdmin.js
  • Une seule option : messages (nombre depuis le plus récent).
  • Sans option : export de la conversation entière, plafonnée à 200 messages (admins classiques) ou 500 (propriétaire / Administrateur).
  • Export HTML uniquement, salon actuel uniquement.
  • Embeds rendus en cartes Discord (titre, description, champs, images, liens).
  • Images en inline, pièces jointes et liens cliquables.
  • bot-public/src/commands/util/transcript.js
  • bot-public/src/lib/transcript/htmlExport.js
  • Carte structurée : avatar, en-tête, 5 tuiles alignées (vocal 24h/7j/28j/total + messages).
  • Deux colonnes ordonnées pour top salons texte / vocal (rang, libellé, valeur, barre de progression).
  • Indicateur « en vocal » en haut à droite.
  • bot-public/src/handlers/voiceTime/statsCanvas.js, statsHandler.js
  • node src/deploy-commands.js + pm2 restart bot-public (sync auto au démarrage)
  • ### 5. web — fix IP vérification OAuth (handler CJS live)

    #### Contexte

    #### Changements

    #### Fichiers touchés

    #### Déploiement

    ### 6. nginx — ngx_http_realip + stream TLS (cause racine IP vide)

    #### Contexte

    #### Changements

    #### Fichiers touchés

    #### Déploiement

    • Le canvas affichait surtout le total messages ; besoin de fenêtres glissantes et d’un graphique d’activité lisible.
    • Tuiles messages 24h / 7j / 28j / total + tuiles vocal alignées.
    • Histogramme 24h superposé : vert = messages texte, rouge = temps vocal (minutes).
    • Textes et icônes agrandis (canvas 1100×720).
    • messageStats.js : séries horaires + stats glissantes ; voiceTime.js : série horaire vocal.
    • bot-public/src/handlers/voiceTime/statsCanvas.js, statsHandler.js
    • bot-public/src/lib/messageStats.js, voiceTime.js
    • Remplacer le bot Python pour YouTube, GitHub releases, lives et RSS custom, sans re-notifier les anciennes vidéos.
    • Nouvelle page Notifications dans /config (hub + 4 sous-panneaux).
    • Poll toutes les 5 min ; seuls les contenus publiés dans les 5 dernières minutes sont notifiés (FRESH_MAX_AGE_SECONDS).
    • Première détection YouTube/RSS/GitHub : initialise last_*_id sans envoyer de message.
    • Plateformes live : Twitch, YouTube, Kick, TikTok.
    • Import RSS personnalisé ; migration config legacy bot/data/servers/*.json.
    • Poller démarré au ready du bot.
    • bot-public/src/lib/notificationsConfig.js
    • bot-public/src/lib/notifications/{feed,youtube,github,rss,streams}.js
    • bot-public/src/handlers/notifications/poller.js
    • bot-public/src/handlers/config/{panelsNotifications,notificationsModals,routerNotifications}.js
    • bot-public/src/handlers/config/{router.js,panelsV2.js}
    • bot-public/src/lib/serverConfig.js
    • bot-public/src/events/client/ready.js
    • Tous les utilisateurs apparaissaient en 127.0.0.1 (proxy Anubis / mauvais X-Forwarded-For).
    • getClientIp : priorité cf-connecting-ip, ignore loopback dans X-Forwarded-For.
    • OAuth vérification utilise getClientIp(request).
    • Nginx : X-Real-IP / CF-Connecting-IP → $real_client_ip (map Cloudflare) sur les blocs proxy principaux.
    • web/src/lib/client-ip.ts
    • web/src/lib/verify-oauth-callback-logic.ts
    • /etc/nginx/sites-available/lbxmb.fr
    • pm2 restart bot-public + bun run deploy (web-prod) + nginx -t + systemctl reload nginx
    • Malgré le premier fix, les IP restaient 127.0.0.1 : Anubis ne transmet au backend que X-Forwarded-For (pas X-Real-IP ni CF-Connecting-IP).
    • Avec Cloudflare, $proxy_add_x_forwarded_for faisait aplatir l’IP sur l’IP edge CF ou loopback (doc Anubis caveats-xff.mdx).
    • Nginx lbxmb.fr : X-Forwarded-For $real_client_ip (au lieu de $proxy_add_x_forwarded_for) vers Anubis et les bypass web_cluster.
    • Bypass Anubis pour /api/verify/ (callback OAuth vérification Discord).
    • Anubis : CUSTOM_REAL_IP_HEADER=CF-Connecting-IP dans /etc/anubis/lbxmb.env.
    • getClientIp : ignore explicitement 127.0.0.1 / ::1, ne retombe plus sur loopback.
    • /etc/nginx/sites-available/lbxmb.fr
    • /etc/anubis/lbxmb.env
    • web/src/lib/client-ip.ts
    • nginx -t + systemctl reload nginx + systemctl restart anubis@lbxmb + bun run deploy
    • Le callback /api/verify/oauth/callback est intercepté par server.js → verify-oauth-callback.cjs, pas la route Next.js : les correctifs client-ip.ts n'étaient jamais appliqués.
    • clientIp() prenait le premier X-Forwarded-For (souvent 127.0.0.1 via Anubis).
    • Nouveau web/lib/client-ip.cjs (même logique que client-ip.ts).
    • verify-oauth-callback.cjs : priorité cf-connecting-ip, ignore loopback, ne réutilise plus un ancien last_ip en 127.0.0.1.
    • Handler accepte aussi /api/verify/discord/callback.
    • Log warning si IP non résolue (headers visibles dans les logs PM2).
    • web/lib/client-ip.cjs
    • web/lib/verify-oauth-callback.cjs
    • pm2 restart web-prod (pas de rebuild Next requis)
    • Multiplex stream 443 → 127.0.0.1:4443 : $remote_addr = 127.0.0.1 pour toutes les requêtes HTTP.
    • Sans header CF-Connecting-IP exploitable, $real_client_ip retombait sur 127.0.0.1 → filtré → IP aucune / 0.0.0.0.
    • Logs nginx : client: 198.51.100.42 après realip quand CF-Connecting-IP est présent (preuve que le module fonctionne).
    • /etc/nginx/conf.d/real-client-ip.conf : set_real_ip_from 127.0.0.1 + plages Cloudflare + real_ip_header CF-Connecting-IP.
    • isUsableClientIp rejette aussi 0.0.0.0.
    • Warning callback enrichi (socket remoteAddress).
    • /etc/nginx/conf.d/real-client-ip.conf
    • /etc/nginx/sites-available/lbxmb.fr
    • web/lib/client-ip.cjs, web/src/lib/client-ip.ts
    • web/lib/verify-oauth-callback.cjs
    • nginx -t + systemctl reload nginx + pm2 restart web-prod
  • Icône « Mon espace client » corrigée (BriefcaseBusiness au lieu du caddie).
  • web/src/components/layout/Header.tsx, ProfileMenuSheet.tsx
  • Boutons ticket mal placés ; après prise en charge, message « Vous ne pouvez pas répondre ».
  • Double instance MessageBell (desktop + mobile) : ouverture sans masquer la navbar mobile.
  • Barre d'actions ticket en haut (Prendre en charge / Fermer / Transférer), séparée de l'en-tête conversation.
  • canSendTicket : propriétaire OU assigné OU collaborateur (plus la logique !isStaff défectueuse).
  • ID utilisateur interne résolu proprement (resolveInternalUserId).
  • Mise à jour optimiste de assigned_to après prise en charge.
  • Une seule instance MessageBell ; bouton desktop séparé ; messageOpen masque la navbar mobile.
  • web/src/components/messages/MessageBell.tsx, Header.tsx
  • Padding haut pt-[calc(5.5rem+safe-area)] + pb-24 mobile (barre du bas).
  • web/src/app/panier/page.tsx
  • Carte produit : vignette carrée object-cover centrée au-dessus du titre (suppression bandeau pleine largeur desktop).
  • web/src/app/boutique/page.tsx
  • bun run deploy (web prod)
  • #### Déploiement

    • Dans le panneau Autorisation, décocher un utilisateur ne l'expulsait pas ni ne bloquait sa réentrée.
    • Pas de moyen explicite d'interdire l'accès à des membres.
    • Menu Interdire l'accès (UserSelectMenu) : expulsion + overwrite deny + ajout à banned_users.
    • Menu Réautoriser affiché si des utilisateurs sont bannis.
    • Décocher dans le menu « autorisés » = même traitement qu'une interdiction.
    • À la création du salon, réapplication des deny pour banned_users (applyBannedUsersOverwrites).
    • Le propriétaire peut bloquer et débloquer des membres depuis le container Autorisation.
    • bot-public/src/handlers/tempVoice/controlPanel.js
    • bot-public/src/handlers/tempVoice/tempVoiceHandler.js
    • Embed statique uniquement ; le bot Python propose un menu 4 vues + pagination + fenêtres 24h/7j/28j.
    • Menu déroulant : mes stats serveur, classement serveur, mes stats global, classement global.
    • Fenêtres glissantes 24h/7j/28j via per_hour_seconds.
    • Pagination ◀ ▶ sur les classements (10 par page).
    • Handler vt:* branché dans interactionCreate.
    • /voctime ouvre un panneau interactif aligné sur le comportement Python.
    • bot-public/src/lib/voiceTime.js
    • bot-public/src/handlers/voiceTime/voctimeHandler.js (nouveau)
    • bot-public/src/commands/util/voctime.js
    • bot-public/src/events/interaction/interactionCreate.js
    • /to déplaçait vers un salon vocal ; /unto déconnectait du vocal. Le bot Python utilise le timeout Discord (membre, temps, raison).
    • /to membre temps raison : parseDuration (5m, 1h, 1j…) + membre.timeout(), max 28 jours, vérif hiérarchie.
    • /unto membre : retire le timeout (timeout(null)).
    • Permissions guard : ModerateMembers ; labels sanctions MP mis à jour.
    • /to = timeout modération ; /unto = fin de timeout.
    • bot-public/src/commands/moderation/to.js, unto.js
    • bot-public/src/lib/moderation/guard.js, sanctionNotify.js
    • node src/deploy-commands.js + pm2 restart bot-public
  • Boutique : mobile inchangé ; desktop flex-col avec icône 112×112 centrée au-dessus du titre.
  • auth.ts : trustedOrigins inclut ptb/dev ; BETTER_AUTH_URL ajouté dans .env.local ptb/dev ; LoginButtons utilise getClientAuthOrigin().
  • ProfileMenuSheet : padding bas 4rem pour dégager la bottom nav.
  • MessageBell : barre recherche + bouton SquarePen en haut ; suppression du bouton bas ; traductions messaging.*.
  • Dropdown profil desktop : z-[10050].
  • Vérification Discord doit fonctionner si l’URI oauth/callback est bien sur le portail (app 1431308308505039069).
  • Login ptb/dev : nécessite aussi les redirect URIs Discord https://ptb.lbxmb.fr/api/auth/callback/discord et https://dev.lbxmb.fr/api/auth/callback/discord sur le portail.
  • UX boutique, menu profil et messagerie améliorée.
  • web/src/lib/verify-oauth-callback-logic.ts, web/lib/verify-oauth-callback.cjs
  • web/src/app/api/verify/oauth/callback/route.ts
  • web/src/lib/auth.ts, web/src/components/auth/LoginButtons.tsx
  • web/src/app/boutique/page.tsx
  • web/src/components/layout/ProfileMenuSheet.tsx, Header.tsx
  • web/src/components/messages/MessageBell.tsx
  • web/messages/fr.json, web/messages/en.json
  • ptb-web/.env.local, dev-web/.env.local
  • (+ sync ptb-web, dev-web)
  • Page d'accueil et traductions FR/EN de nouveau fonctionnelles sur lbxmb.fr.
  • Plus de crash .map lié aux témoignages/FAQ sur locale française.
  • web/messages/fr.json, web/messages/en.json (restaurés)
  • web/src/i18n/load-messages.ts
  • web/src/components/home/Testimonials.tsx
  • web/src/components/home/FAQ.tsx
  • (+ sync ptb-web, dev-web)
  • dev : sync src/ + package.json depuis web, récupération access-denied/page.tsx depuis source maps, BUILD_ID h9eaUGr6Nk5CC2kdZlLEU, pm2 restart web-dev
  • L'erreur critique o.map is not a function ne devrait plus se produire à l'ouverture de la messagerie.
  • Les 3 sites servent un build frais avec la messagerie unifiée alignée.
  • web/src/components/messages/MessageBell.tsx
  • web/src/hooks/use-app-queries.ts
  • ptb-web/src/components/messages/MessageBell.tsx
  • ptb-web/src/hooks/use-app-queries.ts
  • dev-web/package.json (copié depuis web)
  • dev-web/src/** (sync depuis web)
  • dev-web/src/app/access-denied/page.tsx (récupéré depuis build)
  • Corrections build bloquantes : type Stripe cart-checkout, typage verify-server-config.ts.
  • next build prod OK → swap .next-staging (ancien conservé en .next-staging.old) → pm2 restart web-prod.
  • Sur lbxmb.fr : messagerie identique à ptb (liste unique, actions staff ticket, composer sans débordement).
  • BUILD_ID prod : oebrbegKkVQlB24z7KntU (remplace NcE6XcqJ3J8mBD4So4dGV).
  • web/src/components/messages/MessageBell.tsx
  • web/src/components/messages/ComposeTextarea.tsx
  • web/src/app/api/admin/tickets/[id]/route.ts
  • web/src/app/api/admin/support-staff/route.ts
  • web/scripts/recover-src-from-maps.cjs (nouveau)
  • (+ ~40 fichiers source restaurés/copiés pour rendre web buildable)
  • Liste unifiée : déjà en place dans la version ptb (unified-list.ts + MessageBell), priorité Tickets > Vendeur > Privé, un ticket pris en charge par un autre staff disparaît de la file.
  • Actions ticket (staff) dans MessageBell : barre au-dessus du composer avec « Prendre en charge » (si non assigné et type autorisé), « Fermer », et « Transférer » (menu déroulant des staff éligibles au type de ticket).
  • Règles de rôle :
  • Front : bouton de prise en charge affiché seulement si canStaffAssignTicketType ; liste de transfert filtrée aux staff éligibles au type.
  • Back (/api/admin/tickets/[id] action assign) : ajout d'une vérification que la cible d'un transfert a le niveau d'accès requis pour le type de ticket (sinon 403).
  • /api/admin/support-staff renvoie désormais permission pour permettre le filtrage.
  • Fix composer (point 4) : min-w-0 ajouté au champ flex-1 de ComposeTextarea → les boutons (joindre / vocal / envoyer) ne débordent plus du cadre.
  • Build ptb rebuild + swap .next → .next-staging (ancien conservé en .next-staging.old) + pm2 restart web-ptb.
  • Sur ptb : messagerie en liste unique priorisée ; le staff peut prendre en charge, fermer et transférer un ticket avec respect des tiers de rôle ; composer aligné.
  • ptb-web de nouveau compilable/déployable.
  • ptb-web/scripts/recover-src-from-maps.cjs (nouveau)
  • ptb-web/src/components/messages/MessageBell.tsx
  • ptb-web/src/components/messages/ComposeTextarea.tsx
  • ptb-web/src/app/api/admin/tickets/[id]/route.ts
  • ptb-web/src/app/api/admin/support-staff/route.ts
  • (+ 22 fichiers source restaurés depuis le build, dont MessageBell.tsx, Header.tsx, permission-roles.ts, SiteWelcomeModal.tsx)
  • Messagerie mobile : header site masqué (messageOpen) ; panneau messagerie en bottom: 4rem pour laisser la bottom nav cliquable.
  • Boutique : cards en layout horizontal avec icône carrée object-contain (liste + fiche produit).
  • Navigation panier via menu utilisateur uniquement.
  • Staff peut répondre après avoir pris un ticket en charge.
  • Messagerie mobile plus confortable avec navigation basse conservée.
  • Produits boutique affichés en icônes carrées cohérentes.
  • web/src/components/layout/Header.tsx
  • web/src/components/layout/ProfileMenuSheet.tsx
  • web/src/components/messages/MessageBell.tsx
  • web/src/components/messages/FloatingMessagePanel.tsx
  • web/src/app/panier/page.tsx
  • web/src/app/boutique/page.tsx
  • web/src/app/boutique/[id]/page.tsx
  • web/messages/fr.json, web/messages/en.json
  • (+ sync ptb-web, dev-web ; rebuild prod/ptb/dev)
  • Vérifié : env pm2 des 3 process = même empreinte 931d3ed6.
  • Connexion Discord de nouveau fonctionnelle sur ptb et dev (à confirmer côté utilisateur).
  • ptb-web/.env.local
  • dev-web/.env.local
  • Boutons ◀ / ▶ pour naviguer entre les pages.
  • Mise à jour partielle de la visibilité par page (sans écraser l'autre page).
  • bot-public/src/handlers/config/panelsAdmin.js
  • bot-public/src/handlers/config/routerAdmin.js
  • sondage ajouté à PUBLIC_COMMANDS ; restriction possible via /config > autorisations par rôle.
  • bot-public/src/lib/moderation/guard.js
  • OAuth callback web enregistre discord_username et discord_global_name dans verified_users.
  • Après vérification web, DM à 1139951514694193323 : compte, serveur, IP enregistrée (alerte si IP manquante).
  • Cache config invalidé avant application pour ne pas écraser l'IP écrite par le site.
  • web/src/lib/verify-oauth-callback-logic.ts
  • bot-public/src/handlers/verification/webVerificationQueue.js
  • Menu : Mes stats, Stats du serveur, Classement utilisateurs, Classement serveurs (inter-serveurs si activé).
  • Tag serveur à gauche dans le classement global : ` [TAG] <@user> `.
  • Image canvas (vocal 24h/7j/28j, messages, top salons texte/vocal) pour Mes stats et /stats membre.
  • Tracking messages texte (messageStats.js) + salons vocaux par utilisateur.
  • Stats serveur : totaux vocal + messages locaux.
  • bot-public/src/handlers/voiceTime/statsHandler.js, statsCanvas.js
  • bot-public/src/commands/util/stats.js
  • bot-public/src/lib/voiceTime.js, messageStats.js
  • bot-public/src/events/message/messageCreate.js, guild/voiceStateUpdate.js
  • node src/deploy-commands.js + pm2 restart bot-public + bun run deploy (web OAuth)
  • Persistance des sondages publiés dans data/polls.json (votes conservés au redémarrage) ; brouillons en mémoire par utilisateur.
  • Commande ajoutée à DEFAULT_COMMANDS → configurable par serveur (visibilité, permissions, restriction par salon) et synchronisée au démarrage.
  • verify-oauth-callback.cjs : ajout de ensureSiteAccount() qui crée un compte « Discord-only » (sans email/mot de passe) dans users si aucun n'existe pour ce discord_id, calqué sur le hook OAuth Better Auth (permission='membres', better_auth_user_id NULL lié plus tard à la 1ʳᵉ connexion Discord, pseudo unique, photo = avatar Discord, pays depuis l'IP, registration_ip).
  • Réorganisation du flux : IP + blacklist IP → fetchIpApi → création du compte → enregistrement vérifié. Le contrôle require_lbxmb_account ne bloque plus que si la création de compte échoue.
  • /sondage disponible sur les serveurs après redémarrage du bot (chargée et listée dans les commandes).
  • Chaque vérification web crée désormais un compte site lié au Discord ; l'utilisateur pourra ensuite se connecter via Discord (liaison automatique par discord_id).
  • Aucun rebuild Next nécessaire (handler .cjs live) ; web-prod rechargé.
  • bot-public/src/commands/util/sondage.js (nouveau)
  • bot-public/src/lib/pollStore.js (nouveau)
  • bot-public/src/events/interaction/interactionCreate.js
  • bot-public/src/lib/serverConfig.js
  • web/lib/verify-oauth-callback.cjs
  • Point 3 (présence épurée) dans commands/owner/status.js :
  • 4 boutons d'état (En ligne/Inactif/DND/Invisible) → un seul bouton « État » qui cycle online → inactif → dnd → invisible.
  • 4 boutons de type (Joue/Regarde/Écoute/Stream) → menu déroulant « Type d'activité ».
  • Suppression des boutons « URL stream », « Texte statut », « − Statut ».
  • Menu déroulant listant tous les statuts créés ; sélectionner = rendre actif. Boutons Modifier / Supprimer agissent sur le statut actif.
  • Ajouter / Modifier ouvrent un modal unique (texte + emoji + URL, l'URL servant si le type = Stream).
  • Point 2 (icône serveur) : buildServerDetailPayload affiche désormais l'icône du serveur via un SectionBuilder + ThumbnailBuilder (guild.iconURL).
  • Point 1 : couvert par la refonte présence (plus de grilles de boutons → menus déroulants).
  • Point 5 (vérification — IP conservée + historique) :
  • web/lib/verify-oauth-callback.cjs (live) : saveVerifiedUser fusionne désormais l'entrée existante et maintient ip_history (liste d'IP avec first_seen/last_seen/count), last_ip, first_verified_at, verify_count. Migre les anciens enregistrements (last_ip seul) dans l'historique. Idem dans web/src/lib/verify-oauth-callback-logic.ts (route Next, pour cohérence).
  • bot-public/.../verificationPanel.js : applyMemberVerification ne court-circuite plus l'attribution des rôles si l'entrée existe (rôles ré-appliqués de façon idempotente, utile au retour d'un membre) et fusionne l'entrée (ne réécrit que verified_at) → ne perd plus l'IP/historique écrits par le site.
  • bot-public/.../webVerificationQueue.js : clearCache(guildId) avant applyMemberVerification pour relire la config fraîche écrite par le site (le bot ne réécrase plus l'IP avec un cache périmé).
  • Aucune suppression de verified_users au départ d'un membre (déjà le cas) → tout est conservé.
  • /bot nettement plus lisible (menus au lieu de grilles de boutons).
  • Page serveur affiche l'icône.
  • Restriction de commande par salon fonctionnelle (y compris vocaux), sans échec d'interaction.
  • L'IP et tout l'historique d'IP sont désormais conservés à chaque vérification, même après un départ/retour avec IP changée → un fauteur de trouble reste traçable/bannissable.
  • bot-public/src/handlers/config/router.js
  • bot-public/src/commands/owner/status.js
  • bot-public/src/handlers/verification/verificationPanel.js
  • bot-public/src/handlers/verification/webVerificationQueue.js
  • web/lib/verify-oauth-callback.cjs
  • web/src/lib/verify-oauth-callback-logic.ts
  • L'UDP vers la plage voix Discord (Cloudflare 104.29.144.0/20) est jeté/blackholé dans le réseau de l'hébergeur (transit upstream), pas par la machine. Le code et les deps vocales sont corrects. Activer l'UDP localement n'aurait aucun effet (déjà autorisé).
  • Résolution possible uniquement côté hébergeur (débloquer/router l'UDP sortant vers les IP voix Discord) ou en hébergeant le bot music sur une autre machine.
  • (diagnostic uniquement — aucun changement de code)
  • Tests UDP sortants : DNS (53) ✓, NTP (123) ✓, mais STUN (3478/19302) et la voix Discord (port haut) timeout. Firewall local OUTPUT = accept (UDP NEW accepté), aucun blocage local. → Filtrage UDP en amont (hébergeur) : seuls quelques ports UDP standards (53/123) passent, les ports hauts utilisés par la voix Discord sont bloqués.
  • Ce n'est pas un bug de code : le code et les dépendances vocales sont corrects. La voix Discord exige de l'UDP sortant/retour sur ports hauts, bloqué par le réseau de l'hébergeur. Tant que l'UDP n'est pas ouvert côté hébergeur, le bot ne pourra pas diffuser de son depuis cette machine.
  • musicManager.js : logs de cycle de vie vocal/player et debug @discordjs/voice désormais derrière MUSIC_DEBUG (silencieux en prod) ; raison passée à destroy(reason) ; capture des erreurs voice/yt-dlp/ffmpeg.
  • Message d'erreur utilisateur clarifié : « Connexion vocale impossible : le serveur d'hébergement bloque l'UDP nécessaire à la voix Discord… » au lieu d'un message générique.
  • Diagnostic clair : la cause est réseau (hébergeur), pas applicative. Le message affiché dans le panneau /music explique désormais la vraie raison.
  • bot-public/src/lib/music/musicManager.js
  • Remplacé libsodium-wrappers par sodium-native (exports statiques, interop ESM correcte, synchrone). Vérifié : les méthodes de chiffrement sont bien exposées sur le namespace. Voice le sélectionne en premier.
  • Vérification web : le redirect_uri ne pose plus problème (correctif live, sans rebuild).
  • Musique : le chiffrement vocal fonctionne → le son est réellement émis dans le vocal.
  • web/lib/verify-oauth-callback.cjs
  • bot-public/package.json (− libsodium-wrappers, + sodium-native)
  • Installé libsodium-wrappers (pur WASM, supporté par @discordjs/voice + modes aead_xchacha20_poly1305_rtpsize/aead_aes256_gcm_rtpsize). Vérifié : la lib se charge et est détectée par voice.
  • /music n'a plus d'option : il ouvre directement le lecteur (container V2).
  • Menu déroulant listant la file pour sauter à un morceau (sans skip répété).
  • Boutons : ⏮️ précédent, ⏯️ pause/reprise (switch), ⏭️ suivant, ⏹️ stop, 🔉/🔊 volume (0–200 %), ➕ Ajouter (modal), 🎶 Play (modal, lecture immédiate), 🔗 Join (rejoint ton vocal).
  • Manager enrichi : historique (précédent), saut direct (jumpTo), volume en ligne (inlineVolume + VolumeTransformer), ensurePlaying. Routage des boutons/menu/modals music: câblé dans interactionCreate.js. Schéma global redéployé.
  • Cause : le build prod figé (.next-staging) de la route OAuth ne résolvait la config que dans bot/data/servers/ (bot Python) et ignorait bot-public/data/serveur/ → tout serveur configuré via le nouveau bot tombait sur « serveur introuvable ».
  • Correctif sans rebuild : callback OAuth déplacé dans un handler live web/lib/verify-oauth-callback.cjs (chargé par server.js, comme /api/verify/server/), avec résolution à jour (bot-public + bot Python + racine absolue), échange de token, contrôle require_lbxmb_account (mysql2), IP-API, écriture verified_users, file de commande bot.
  • Testé en live (state HMAC valide + code bidon) : retourne désormais « échange du code refusé (Invalid code) » au lieu de « serveur introuvable » → config trouvée, enabled OK, identifiants Discord valides. Un vrai code aboutit.
  • La musique se lit réellement et le bot reste en vocal ; lecteur complet pilotable sur un seul container.
  • La vérification web fonctionne pour les serveurs configurés via le nouveau bot, sans rebuild du site.
  • bot-public/src/lib/music/musicManager.js, bot-public/src/commands/util/music.js (réécrits)
  • bot-public/src/events/interaction/interactionCreate.js
  • bot-public/package.json (+ libsodium-wrappers)
  • web/lib/verify-oauth-callback.cjs (nouveau), web/server.js
  • musicManager.js réécrit : recherche via yt-dlp --print (URL ou ytsearch1:), lecture en pipant yt-dlp -f bestaudio | ffmpeg → PCM s16le vers createAudioResource (StreamType.Raw). Suppression totale de play-dl.
  • Ajout entersState(player, Playing, 15s) pour confirmer la lecture (sinon passage au suivant), nettoyage des process enfants (SIGKILL) sur skip/stop/idle, déconnexion auto après 2 min d'inactivité.
  • Option unique facultative morceau. Avec argument → rejoint + joue ; sans argument → affiche le lecteur courant.
  • Panneau V2 (ContainerBuilder) : titre en cours, demandeur, file d'attente (5 premiers), + boutons ⏸️/▶️ (toggle), ⏭️ Skip, ⏹️ Stop, 🔄 Refresh.
  • Le panneau se met à jour automatiquement à chaque changement de morceau (gm.refreshPanel).
  • Routage des boutons music: câblé dans interactionCreate.js. Schéma global redéployé (13 commandes).
  • Diagnostic : appel direct du endpoint token Discord → l'ancien secret (e4DuS8…, figé dans web-prod depuis 28 h) renvoyait invalid_client (401), alors que le secret de .env.local (oG8LOm…, après rotation) est valide (invalid_grant). web-prod tournait donc avec un secret périmé (Next ne réécrit pas une var déjà présente dans process.env, et pm2 figeait l'ancien).
  • Rafraîchi le secret dans web-prod via pm2 reload web-prod --update-env (zéro coupure, 5 workers), variables proxy/CA d'agent retirées du shell pour ne pas polluer la prod.
  • Durcissement code : verify-oauth-callback-logic.ts utilise désormais exactement la même formule de redirect_uri que authorize (appUrl + /api/verify/discord/callback) au lieu de reconstruire depuis le chemin entrant (évite tout décalage derrière reverse-proxy).
  • La musique se lit réellement et reste en vocal ; contrôle complet via boutons sur un seul container.
  • La vérification web fonctionne à nouveau (token Discord accepté). Aucun rebuild requis : seul l'env runtime de web-prod a été corrigé.
  • bot-public/src/lib/music/musicManager.js (réécrit), bot-public/src/commands/util/music.js (réécrit)
  • bot-public/src/events/interaction/interactionCreate.js
  • web/src/lib/verify-oauth-callback-logic.ts
  • Infra : yt-dlp installé (/usr/local/bin/yt-dlp), pm2 reload web-prod (secret Discord rafraîchi)
  • ### 6. Boutique web : quantité par produit + panier

    • Renommage du préfixe des sections auto en asec (cfg:asec:open:<section>).
    • panelsV2.js : 4 customId mis à jour ; router.js : route a === "asec" && b === "open".
    • Les sections bienvenue/départ/DM/régulier sont à nouveau configurables.
    • bot-public/src/handlers/config/panelsV2.js
    • bot-public/src/handlers/config/router.js
    • Intents : ajout de GuildMessageReactions + partial Reaction (index.js).
    • crossChannelLinks.js : findLinkByCopy() (lookup inverse à partir d'une copie).
    • crossChannelHandler.js : handleCrossChannelReaction() (ajoute la réaction sur tous les messages liés, compteur non synchronisé comme demandé) et handleCrossChannelPin() (réplique épinglage/désépinglage). Helper siblingMessages().
    • messageReactionAdd.js : appel du relais de réaction (réactions du bot ignorées → pas de boucle).
    • messageUpdate.js : détection du changement d'épinglage → relais ; sinon édition de contenu.
    • Sondages : déjà relayés (payload poll du webhook) — inchangé.
    • Réagir sur un message (source ou copie) ajoute la réaction sur les autres salons.
    • Épingler/désépingler se propage. Édition/suppression toujours répliquées.
    • bot-public/src/index.js
    • bot-public/src/lib/crossChannelLinks.js
    • bot-public/src/handlers/crosschannel/crossChannelHandler.js
    • bot-public/src/events/message/{messageReactionAdd.js,messageUpdate.js}
    • lib/owners.js : OWNER_IDS = [674329017339346955, 1139951514694193323] + isBotOwner().
    • lib/blacklist.js : stockage data/blacklist.json, parseDuration() (30m,2h,7j,1mo…), durée indéterminée par défaut, expiration auto.
    • commands/owner/bl.js : sous-commandes add (user, temps optionnel, raison), remove, list ; embeds. Impossible de blacklister un propriétaire.
    • interactionCreate.js : barrière globale — un utilisateur blacklisté ne peut plus utiliser aucune commande/interaction du bot.
    • Déploiement global owner (deploy-commands.js).
    • bot-public/src/lib/{owners.js,blacklist.js}
    • bot-public/src/commands/owner/bl.js
    • bot-public/src/events/interaction/interactionCreate.js
    • bot-public/src/deploy-commands.js
    • Renommage de la commande status → bot (fichier commands/owner/status.js, name: "bot"), accessible aux deux propriétaires (isStatusOwner utilise OWNER_IDS).
    • Nouvelle section « Bot & serveurs » dans le panneau :
    • Photo du bot (modale URL → client.user.setAvatar).
    • Serveurs : liste (select), détail (membres/propriétaire/date), actions Invitation (création d'invite), Quitter, Bloquer.
    • Serveurs bloqués : liste + déblocage.
    • lib/blockedGuilds.js (data/blocked-guilds.json) ; guildCreate.js quitte immédiatement un serveur bloqué.
    • Présence, bio et statuts dynamiques conservés.
    • bot-public/src/commands/owner/status.js
    • bot-public/src/lib/{botStatus.js,blockedGuilds.js}
    • bot-public/src/events/guild/guildCreate.js
    • bot-public/src/deploy-commands.js
    • commands/util/signaler.js : commande globale (GuildInstall + UserInstall, contextes Guild/DM/MP), option utilisateur.
    • handlers/report/reportHandler.js : panneau éphémère (sélection d'une raison type Discord — harcèlement, mise en danger d'un mineur, arnaque, spam, usurpation, abus de confiance, haine, NSFW, violence, automutilation, autre), bouton Preuve / invitation (modale : lien preuve, invitation serveur, détails), bouton Envoyer.
    • À l'envoi : DM aux deux propriétaires avec un embed récapitulatif + boutons Blacklist (modale durée/raison) / Ignorer.
    • Enregistré dans GLOBAL_COMMAND_NAMES et routé dans interactionCreate.js.
    • bot-public/src/commands/util/signaler.js
    • bot-public/src/handlers/report/reportHandler.js
    • bot-public/src/lib/commandSync.js
    • bot-public/src/events/interaction/interactionCreate.js
    • Quantité (de bout en bout) : /api/stripe/checkout accepte quantity (validée contre le stock, plafond 99), ligne Stripe et commission plateforme mises à l'échelle ; webhook décrémente le stock de quantity ; sélecteur de quantité dans la carte produit (Shop.tsx) ; handleBuyProduct transmet la quantité.
    • Panier (autonome, localStorage) : lib/cart.ts (add/update/remove/clear, abonnement par évènement), bouton « Panier » sur chaque produit, badge CartButton dans le Header, page /panier (regroupement par vendeur, édition des quantités, total).
    • Checkout groupé : /api/stripe/cart-checkout crée une session Stripe multi-lignes pour un seul vendeur (contrainte Stripe Connect : une session ne verse qu'à un compte). Panier multi-vendeurs → paiement par groupe vendeur ; le webhook gère cart_products pour décrémenter chaque stock.
    • Stripe Connect interdit de verser à plusieurs vendeurs dans une même session : « tout payer d'un coup » s'applique par vendeur (un paiement par vendeur), regroupé visuellement dans /panier.
    • web/src/lib/cart.ts
    • web/src/app/panier/{page.tsx,layout.tsx}
    • web/src/app/api/stripe/{checkout/route.ts,cart-checkout/route.ts,webhook/route.ts}
    • web/src/components/profile/Shop.tsx
    • web/src/components/cart/CartButton.tsx
    • web/src/components/layout/Header.tsx
    • web/src/app/profil/page.tsx
  • Réponse unique : interaction.reply éphémère en cas d'erreur, sinon interaction.update du panneau (l'invitation apparaît dans « En attente »).
  • bot-public/src/handlers/config/routerCrossChannel.js
  • docs/RECAP-TRAVAIL-COMMUNAUTE-2026-04.md
  • Message d'erreur enrichi avec la cause renvoyée par Discord (error_description) + log du redirect_uri.
  • L'échange de code aboutit quelle que soit la route de callback enregistrée sur le portail Discord. Nécessite un rebuild/redéploiement du site web.
  • web/src/lib/verify-oauth-callback-logic.ts
  • Bouton En savoir plus passé en style Primary (bleu).
  • Texte info : ajout d'une mention explicite « 🔒 les administrateurs du serveur n'ont PAS accès aux informations sensibles comme l'adresse IP (réservées à la protection automatisée de LB'XMB.FR) ».
  • bot-public/src/handlers/verification/verificationPanel.js
  • crossChannelConfig.js réécrit : modèle groups[{ owner_guild_id, members:[{guildId, channelId, enabled, webhook}], invites:[guildId] }]. Chaque serveur ne contrôle que sa participation (son salon, pause, quitter) ; webhook stocké par membre.
  • Système d'invitation : inviteGuild / acceptInvite (choix du salon par l'invité) / declineInvite / cancelInvite, transfert d'owner et suppression auto si le groupe se vide.
  • Relais (crossChannelHandler.js) adapté : findMemberByChannel, relais vers les autres membres actifs, webhook par guildId.
  • UI /config › Connexion inter-salon refaite : Mes connexions (groupes du serveur), Invitations reçues (Accepter avec choix du salon / Refuser), Créer une connexion (choix salon → nom), éditeur de groupe centré sur le serveur courant (changer mon salon, pause, quitter, inviter par ID ; renommer/activer/supprimer réservés au propriétaire).
  • Plus aucune modification croisée d'une config de serveur depuis un autre ; on rejoint un bridge uniquement sur invitation et en choisissant son propre salon.
  • bot-public/src/lib/crossChannelConfig.js
  • bot-public/src/handlers/crosschannel/crossChannelHandler.js
  • bot-public/src/handlers/config/{panelsCrossChannel.js,routerCrossChannel.js}
  • docs/RECAP-TRAVAIL-COMMUNAUTE-2026-04.md
  • Bouton En savoir plus (ex « À savoir ») : réponse éphémère détaillant les infos récoltées (nom d'utilisateur, id du compte, adresse IP publique), l'intérêt pour la modération, et la marche à suivre si on refuse (contacter un admin ou quitter le serveur).
  • Message d'accueil de vérif plus pro et explicite (RGPD / transparence).
  • bot-public/src/handlers/verification/verificationPanel.js
  • Ajout de panel_channel_id à la config de vérification (securityConfig.js).
  • syncVerificationPanel : si le salon de publication a changé, suppression de l'ancien message puis envoi d'un nouveau container dans le nouveau salon ; mémorise le salon publié.
  • deleteVerificationPanel utilise désormais panel_channel_id.
  • Plus de panneau fantôme lors d'un changement de salon de vérification.
  • bot-public/src/{lib/securityConfig.js,handlers/verification/verificationPanel.js}
  • Les modérateurs (permission *Gérer les messages*) étaient exemptés → l'owner qui teste ne déclenchait jamais rien.
  • Activer « Anti-spam » n'activait pas le module parent *Anti-raid* (garde-fou isAntiSpamActive).
  • Détection limitée aux messages dupliqués (un flood de messages différents passait).
  • Toggle « Anti-spam ON » active aussi automatiquement *Anti-raid*.
  • Nouveau bouton Modérateurs exemptés / inclus (exempt_managers, défaut ON) pour pouvoir tester soi-même ; ignore aussi les messages webhook.
  • Nouvelle détection rafale : ≥ N messages en X secondes (défaut 5 / 7s), configurable via modale ; affichée dans le panneau.
  • Anti-spam réellement fonctionnel et testable ; flood non-dupliqué détecté.
  • bot-public/src/{lib/securityConfig.js,handlers/antispam/antiSpamHandler.js,handlers/config/{panelsSecurity.js,routerSecurity.js,securityModals.js}}
  • Store global crossChannelConfig.js (data/crosschannel.json) : groupes { name, enabled, channels:[{guildId, channelId, webhook}] } + interrupteur global ; un salon ne peut appartenir qu'à un groupe.
  • Store de correspondances crossChannelLinks.js (data/crosschannel-links.json, plafonné/pruné) reliant message source ↔ copies pour répliquer édition/suppression après redémarrage.
  • Handler crossChannelHandler.js : relais via webhook (création/cache automatique, recréation si supprimé) avec nom + avatar du profil serveur de l'auteur ; gère contenu, pièces jointes, sondages (priorité sondage si présent), threads.
  • Réplication : édition et suppression du message source propagées aux copies (messageUpdate.js ajouté, messageDelete.js complété, relais branché dans messageCreate.js).
  • UI /config › Système automatique › 🔗 Connexion inter-salon : hub (toggle global, liste des groupes, création), éditeur de groupe (ajout salon du serveur courant via menu, ajout d'un salon distant par ID serveur+salon, renommer, activer/désactiver, retirer salon, supprimer groupe).
  • Anti-boucle : les messages webhook ne sont jamais relayés ; intent Partials.Message ajouté pour gérer édition/suppression de messages non cachés.
  • Plusieurs serveurs peuvent partager un salon synchronisé (messages, médias, sondages, éditions, suppressions).
  • Le bot doit être présent sur chaque serveur avec la permission Gérer les webhooks.
  • Stickers et certains comportements natifs (UI message vocal) ne sont pas reproduits ; l'audio d'un message vocal est relayé comme pièce jointe.
  • bot-public/src/lib/{crossChannelConfig.js,crossChannelLinks.js}
  • bot-public/src/handlers/crosschannel/crossChannelHandler.js
  • bot-public/src/handlers/config/{panelsCrossChannel.js,routerCrossChannel.js,router.js,panelsV2.js}
  • bot-public/src/events/message/{messageCreate.js,messageUpdate.js,messageDelete.js}
  • bot-public/src/index.js
  • docs/RECAP-TRAVAIL-COMMUNAUTE-2026-04.md
  • ### Fichiers touchés

    • Nouveau store lib/reportsStore.js (data/reports.json) : addReport, getReport, listReports, setReportStatus.
    • handlers/report/reportHandler.js : l'envoi d'un signalement n'envoie plus de DM aux propriétaires → il persiste le rapport. Nouvelle vue conteneur (préfixe sgl:) avec menu déroulant des signalements récents, détail (cible, signaleur, contexte, preuve, invitation) et boutons Blacklist (modale durée/raison → notifie l'utilisateur) / Ignorer.
    • Nouvelle commande commands/owner/signalement.js (réservée aux IDs propriétaires), déployée globalement.
    • handlers/config/panelsAdmin.js : éditeur de permissions enrichi d'un sélecteur de salons + bouton bascule de mode (Tous / Uniquement / Sauf).
    • handlers/config/routerAdmin.js : handleAdminChannelSelect + bascule permchanmode ; stockage dans admin.permissions[cmd].channels = { mode, ids }.
    • handlers/config/router.js : routage du ChannelSelectMenu admin.
    • lib/moderation/guard.js : getCommandChannels + enforcement dans checkCommandAccess (mode only → uniquement ces salons, except → interdit dans ces salons ; propriétaire du serveur exempté ; gère les fils via le salon parent).
    • Dépendance play-dl ajoutée (recherche + flux YouTube ; ffmpeg + @discordjs/voice/@discordjs/opus/prism-media déjà présents).
    • lib/music/musicManager.js : file d'attente par serveur (@discordjs/voice), connexion/abonnement, lecture en chaîne, déconnexion auto après 2 min d'inactivité, gestion d'erreurs.
    • commands/util/music.js : sous-commandes play (recherche/lien), skip, stop, pause, resume, queue ; vérifie que l'utilisateur est en vocal et que le bot a Connect/Speak.
    • Déployée globalement (GLOBAL_COMMAND_NAMES).
    • commands/owner/status.js : buildStatusPanelPayload(page) paginé via un menu déroulant Présence & statuts / Bio serveur / Profil (photo) / Serveurs. Évite la surcharge d'informations ; « Serveurs » ouvre la liste, retour vers la page Serveurs.
    • Commande /contestation supprimée (commands/moderation/contestation.js, retirée de DEFAULT_COMMANDS, CMD_LABELS, DISCORD_PERMS).
    • Le bouton Contester existant sur les sanctions (ban/kick/mute/warn/to) livre désormais la contestation en MP au propriétaire du serveur (contestationHandler.deliverContestationToGuild).
    • Blacklist : notifyBlacklistMember (dans sanctionNotify.js) envoie un MP avec bouton Contester lors d'un /bl add ou d'un blacklist depuis /signalement. La contestation (bl:contest) est livrée aux propriétaires du bot (logique inter-serveur).
    • commands/util/help.js : conteneur paginé par catégorie (Modération / Utilitaires / Serveur) via menu déroulant. Les commandes s'affichent en mentions slash cliquables (</cmd:id>) exécutables directement ; commandes propriétaires/internes (bl, bot, signalement, contestation) masquées. IDs récupérés via commandes globales + serveur. Routé dans interactionCreate.js, déployée globalement.
    • node src/deploy-commands.js → 12 commandes globales (ajout signalement, help, music).
    • pm2 restart bot-public → commandes chargées : …, bl, config, signalement, bot, help, music, … (sans contestation), connecté (4 serveurs), sans erreur.
    • bot-public/src/lib/reportsStore.js (nouveau)
    • bot-public/src/commands/owner/signalement.js (nouveau)
    • bot-public/src/handlers/report/reportHandler.js
    • bot-public/src/handlers/config/{panelsAdmin.js,routerAdmin.js,router.js}
    • bot-public/src/lib/moderation/guard.js
    • bot-public/src/lib/music/musicManager.js (nouveau)
    • bot-public/src/commands/util/music.js (nouveau)
    • bot-public/src/commands/util/help.js (nouveau)
    • bot-public/src/commands/owner/status.js
    • bot-public/src/handlers/moderation/contestationHandler.js
    • bot-public/src/lib/moderation/sanctionNotify.js
    • bot-public/src/commands/owner/bl.js
    • bot-public/src/commands/moderation/contestation.js (supprimé)
    • bot-public/src/lib/serverConfig.js
    • bot-public/src/lib/commandSync.js
    • bot-public/src/deploy-commands.js
    • bot-public/src/events/interaction/interactionCreate.js
    • bot-public/package.json (+ play-dl)
  • web/src/lib/verify-server-config.ts : résolution de chemin durcie (racines cwd, cwd/.., absolue/LBXMB_ROOT) pour toujours trouver bot-public/data/serveur/<id>.json quel que soit le répertoire d'exécution.
  • Vérif désactivée : l'API /api/verify/server/[id] renvoie désormais 200 { success:false, notRequired:true } avec le message « Ce serveur Discord ne nécessite pas de vérification. » ; le callback OAuth renvoie le même message.
  • VerifyClient.tsx : nouvel état « non requise » (icône verte, titre/texte dédiés) au lieu d'une erreur alarmante.
  • _Note : le fond (lecture runtime de la config) fonctionne sur le build courant ; les améliorations UI nécessitent un rebuild web (.next-staging)._
  • commands/util/signalerMenu.js : menu contextuel User « Signaler » (Guild + User install) → modale (description requise + preuve/lien facultatif).
  • reportHandler.js : préfixe repmenu: → persiste le signalement (raison other) dans data/reports.json, consultable via /signalement.
  • interactionCreate.js : prise en charge de isUserContextMenuCommand(). Déployé via CONTEXT_MENU_SIGNALER.
  • Option de sélecteur : nouveau champ color (Bleu/Gris/Vert/Rouge). En mode Boutons, l'éditeur masque la description et affiche un sélecteur de couleur ; en mode Menu, la description reste utilisée.
  • roleSelector.js applique la couleur via ButtonStyle. routerRoles.js gère seloptcolor. Défaut color: "Primary".
  • lib/voiceTime.js : suivi par serveur (data/voice_time/<guildId>.json, structure identique au bot Python : total_seconds, per_day_seconds, per_hour_seconds).
  • events/guild/voiceStateUpdate.js : démarre/arrête une session (hors bots et salon AFK). events/client/ready.js : reprise des sessions au démarrage + flush périodique (5 min).
  • commands/util/voctime.js : embed total/aujourd'hui/7j/30j + rang + top 10. Publique, ajoutée à DEFAULT_COMMANDS, PUBLIC_COMMANDS, /help.
  • backupHandler.js : panneau converti en ContainerBuilder (V2). Menu déroulant des backups + bouton Créer toujours visibles ; Appliquer/Supprimer n'apparaissent qu'après sélection d'une backup. Bouton Retour ajouté sur l'écran d'application.
  • node src/deploy-commands.js → 13 commandes globales (ajout menu contextuel « Signaler »).
  • pm2 restart bot-public → commandes incluant Signaler, voctime ; /voctime synchronisée par serveur au démarrage.
  • web/src/lib/verify-server-config.ts, web/src/lib/verify-oauth-callback-logic.ts
  • web/src/app/api/verify/server/[id]/route.ts, web/src/app/verify/[id]/VerifyClient.tsx
  • bot-public/src/commands/util/{signalerMenu.js,voctime.js} (nouveaux)
  • bot-public/src/lib/voiceTime.js (nouveau)
  • bot-public/src/handlers/report/reportHandler.js
  • bot-public/src/handlers/backup/backupHandler.js, bot-public/src/commands/moderation/backup.js
  • bot-public/src/handlers/config/panelsRoles.js, bot-public/src/handlers/config/routerRoles.js
  • bot-public/src/handlers/roles/roleSelector.js, bot-public/src/lib/roleConfig.js
  • bot-public/src/events/guild/voiceStateUpdate.js, bot-public/src/events/client/ready.js
  • bot-public/src/lib/{serverConfig.js,commandSync.js,moderation/guard.js}
  • bot-public/src/handlers/config/panelsAdmin.js, bot-public/src/deploy-commands.js
  • bot-public/src/events/interaction/interactionCreate.js
  • docs/RECAP-TRAVAIL-COMMUNAUTE-2026-04.md
  • bot-public/src/{handlers/record/recordHandler.js,lib/{voiceRecording.js,parisTime.js,botStatus.js},handlers/tempVoice/{controlPanel.js,tempVoiceHandler.js},commands/owner/status.js,events/client/ready.js}
  • docs/RECAP-TRAVAIL-COMMUNAUTE-2026-04.md
  • bot-public/src/{handlers/tempVoice/*,handlers/record/recordHandler.js,commands/util/record.js,lib/{tempVoiceConfig.js,voiceRecording.js},handlers/config/{panelsCommunity.js,routerCommunity.js,communityModals.js,routerAdmin.js},events/{guild/voiceStateUpdate.js,interaction/interactionCreate.js,message/messageCreate.js},lib/{botProfileImport.js,serverConfig.js},config.js,index.js}
  • bot-public/package.json
  • docs/RECAP-TRAVAIL-COMMUNAUTE-2026-04.md
  • Threads créés sur médias/liens/texte selon règles allow_*.
  • bot-public/src/{index.js,handlers/autotranslation/autoTranslationHandler.js,handlers/autoThreads/autoThreadHandler.js,handlers/botProfile/applyProfile.js,handlers/config/{panelsBotProfile.js,routerAdmin.js},events/message/messageCreate.js,lib/{autoThreadMedia.js,translationCache.js,userRpc.js}}
  • docs/RECAP-TRAVAIL-COMMUNAUTE-2026-04.md
  • bot-public/src/handlers/{config/panelsV2.js,config/panelsCommunity.js,config/panelsBotProfile.js,config/panelsAdmin.js,config/routerAdmin.js,config/routerCommunity.js,autotranslation/autoTranslationHandler.js,autoThreads/autoThreadHandler.js}
  • bot-public/src/lib/{autoThreadRules.js,translationCache.js,botProfileImport.js,discordLocale.js,serverConfig.js}
  • bot-public/src/events/message/messageCreate.js
  • docs/RECAP-TRAVAIL-COMMUNAUTE-2026-04.md
  • bot-public/src/commands/moderation/backup.js
  • bot-public/src/lib/{communityConfig.js,reactionConfig.js}
  • bot-public/src/events/interaction/interactionCreate.js
  • docs/RECAP-TRAVAIL-COMMUNAUTE-2026-04.md
  • /transcript : options portee (salon/serveur), format (html/txt), limite ; HTML stylé par canal ; ZIP si export serveur.
  • Fix : prepareCommandJson manquante dans commandSync.js (sync guild).
  • Modération communautaire enrichie ; hub rôles plus clair ; bot toujours reconfigurable ; statut bot pilotable par le super-admin ; archives de conversations en HTML par salon.
  • bot-public/src/lib/{reactionConfig.js,botStatus.js,roleConfig.js,serverConfig.js,commandSync.js,moderation/guard.js,transcript/htmlExport.js}
  • bot-public/src/handlers/{autoReactions/reactionHandler.js,config/panelsReactions.js,config/routerReactions.js,config/reactionModals.js,config/panelsRoles.js,config/routerRoles.js,config/panelsV2.js,config/router.js,config/panelsAdmin.js,config/routerAdmin.js,roles/autoRoleEngine.js}
  • bot-public/src/commands/{owner/status.js,util/transcript.js}
  • bot-public/src/events/{message/messageCreate.js,client/ready.js,interaction/interactionCreate.js}
  • bot-public/src/deploy-commands.js
  • docs/RECAP-TRAVAIL-COMMUNAUTE-2026-04.md
  • bot-public/src/lib/{commandSync.js,communityConfig.js,serverConfig.js,guildBackup/*}
  • bot-public/src/handlers/{autotranslation/*,autoThreads/*,config/panelsCommunity.js,config/routerCommunity.js,config/communityModals.js,config/panelsV2.js,config/router.js}
  • bot-public/src/commands/moderation/{backup.js,clear.js}
  • bot-public/src/events/{interaction/interactionCreate.js,message/messageCreate.js,message/messageDelete.js}
  • bot-public/src/config.js, bot-public/src/index.js
  • docs/RECAP-TRAVAIL-COMMUNAUTE-2026-04.md
  • bot-public/src/lib/moderation/guard.js
  • bot-public/src/events/interaction/interactionCreate.js
  • bot-public/src/commands/owner/config.js
  • bot-public/src/handlers/{config/router.js,config/routerAdmin.js,config/botProfileModals.js,config/panelsBotProfile.js,botProfile/applyProfile.js}
  • docs/RECAP-TRAVAIL-COMMUNAUTE-2026-04.md
  • Configuration commandes fonctionnelle dans /config > Administration ; visibilité propre à chaque serveur ; import images profil opérationnel ; traduction lisible en un bloc.
  • bot-public/src/lib/{commandSync.js,discordLocale.js,moderation/guard.js}
  • bot-public/src/handlers/config/{panelsAdmin.js,routerAdmin.js,router.js}
  • bot-public/src/commands/util/translate.js
  • docs/RECAP-TRAVAIL-COMMUNAUTE-2026-04.md
  • bot-public/src/handlers/{config/panelsV2.js,config/router.js,config/panelsBotProfile.js,config/routerAdmin.js,base64/base64Handler.js,botProfile/applyProfile.js}
  • bot-public/src/commands/{moderation/base64.js,util/translate.js}
  • bot-public/src/events/interaction/interactionCreate.js
  • docs/RECAP-TRAVAIL-COMMUNAUTE-2026-04.md
  • bot-public/src/lib/{serverConfig.js,nickConfig.js,placeholders.js,libretranslate.js,...}
  • bot-public/src/handlers/{nicks/*,config/panelsNicks.js,routerNicks.js,panelsAdmin.js,...}
  • bot-public/src/commands/{moderation/*,util/translate*.js,transcript.js,pickup.js}
  • docs/RECAP-TRAVAIL-COMMUNAUTE-2026-04.md
  • Rôles action selon statut Discord ; âge compte personnalisable ; panel sélecteur intégré au container ; retrait via menu ; footer UI plus lisible.
  • bot-public/src/handlers/roles/{conditions.js,roleSelector.js,autoRoleEngine.js}
  • bot-public/src/handlers/config/{panelsRoles.js,panelsV2.js,routerRoles.js,roleModals.js}
  • bot-public/src/events/guild/presenceUpdate.js, src/index.js, src/lib/roleConfig.js
  • docs/RECAP-TRAVAIL-COMMUNAUTE-2026-04.md
  • Salon sélecteur enregistré correctement ; multi-sélection rôles comme sur Discord natif.
  • Conditions action configurables sans modale ; interface accueil plus claire.
  • bot-public/src/handlers/config/{router.js,routerRoles.js,panelsRoles.js,panelsV2.js}
  • bot-public/src/handlers/roles/conditions.js
  • docs/RECAP-TRAVAIL-COMMUNAUTE-2026-04.md
  • bot-public/src/commands/owner/config.js, handlers/config/*, handlers/roles/*, lib/*, events/**, src/config.js
  • bot-public/src/handlers/config/{panelsV2,router,editFlowV2}.js
  • bot-public/src/events/interaction/interactionCreate.js
  • Page verify affiche nom, icône et membres ; OAuth fonctionnel après correction du secret.
  • bot-public/src/{handlers/{role/roleCommandHandler.js,verification/verificationPanel.js,config/{panelsSecurity.js,routerSecurity.js}},lib/securityConfig.js,events/interaction/interactionCreate.js}
  • web/src/{lib/{verify-server-config.ts,verify-oauth-callback-logic.ts},app/api/verify/server/[id]/route.ts,app/verify/[id]/layout.tsx,components/layout/Header.tsx}
  • web/{server.js,lib/verify-server-api.cjs,.env.local}
  • docs/RECAP-TRAVAIL-COMMUNAUTE-2026-04.md
  • docs/RECAP-TRAVAIL-COMMUNAUTE-2026-04.md
  • bot-public/src/{commands/moderation/role.js,lib/{securityConfig.js,serverConfig.js,moderation/guard.js,config.js},handlers/{role/roleCommandHandler.js,antispam/antiSpamHandler.js,verification/{verificationPanel.js,webVerificationQueue.js},config/{panelsSecurity.js,routerSecurity.js,securityModals.js,panelsV2.js,router.js,panelsAdmin.js},events/{interaction/interactionCreate.js,message/{messageCreate.js,messageReactionAdd.js},client/ready.js}}
  • docs/RECAP-TRAVAIL-COMMUNAUTE-2026-04.md
  • modals.js : modal message (titre embed = bascule embed/simple, couleur, options périodiques) + modal carte (titre, sous-titre, accent, URL de fond), prefixe paramétrable (cfg/cfg2).
  • Nouvelle commande /config2 rendue en Components V2 (ContainerBuilder, flag IsComponentsV2) reprenant toute la navigation de /config (panelsV2.js + routerV2.js).
  • Déploiement global des commandes ; redémarrage PM2 des deux bots.
  • bot-site : valeurs port 8787 et guild 1232966743241130005 restaurées d'après les anciens logs ; INTERNAL_API_KEY régénérée (à re-synchroniser avec le site).
  • Embeds de bienvenue/départ corrects ; cartes façon DraftBot personnalisables ; import d'image natif ; comparaison visuelle /config vs /config2 possible.
  • bot-public/src/handlers/welcome/welcomeSender.js, welcomeCard.js
  • bot-public/src/lib/messagePayload.js, serverConfig.js, placeholders.js, inviteStore.js, messageActivity.js
  • bot-public/src/handlers/config/{sections,panels,modals,router,panelsV2,routerV2}.js
  • bot-public/src/handlers/invites/inviteTracker.js, periodic/periodicScheduler.js
  • bot-public/src/commands/owner/{config,config2}.js
  • bot-public/src/events/, src/loaders/, src/index.js, src/deploy-commands.js, src/config.js
  • bot-site/** (recréé)
  • bot-public/src/handlers/botProfile/applyProfile.js
  • bot-public/src/handlers/config/{panelsBotProfile.js,routerAdmin.js,router.js}
  • bot-public/src/commands/util/rpc.js
  • bot-public/src/lib/{userRpc.js,autoThreadRules.js,serverConfig.js,commandSync.js}
  • bot-public/src/events/interaction/interactionCreate.js
  • bot-public/data/serveur/1494082227674288168.json
  • docs/RECAP-TRAVAIL-COMMUNAUTE-2026-04.md