Ouvrir l'app

🧩 Administration : intégrations

Toutes les clés sont des secrets Cloudflare (jamais côté navigateur). Ajoute-les depuis le dossier du projet :

npx wrangler secret put NOM_DU_SECRET

En local, mets-les dans .dev.vars (copie de .dev.vars.example, jamais versionné). Tous les secrets sont facultatifs : sans eux, la fonctionnalité correspondante est simplement désactivée, avec un message qui dit quel secret manque.

Ensuite, règle chaque intégration dans l'appli : 🧩 Intégrations → ⚙️ Réglages (réservé aux admins). Les pastilles en haut montrent ce qui est actif.

Récapitulatif des secrets#

SecretDébloqueCoût indicatif
TURN_KEY_ID, TURN_KEY_API_TOKENRelais TURN Cloudflare : audio/vidéo fiable sur 4G et réseaux d'entrepriseSelon le trafic Cloudflare Realtime
OPENROUTER_API_KEYToute l'IA du serveur : traduction ultra-rapide, comptes-rendus, assistant de l'app de bureau, copilote en directTraduction ≈ 0,04 $ / h et par langue ; copilote ≈ 0,05 à 0,30 $ / h de réunion ; compte-rendu ≈ 0,02 à 0,10 $
ELEVENLABS_API_KEYVoix traduite Premium (ElevenLabs, voix clonées) et la démo vocale≈ 2,2 $ / h de voix (Flash v2.5)
INTG_ENC_KEYChiffrement des jetons de toutes les connexions (MCP en un clic et OAuth classique). Obligatoire pour tout connecteurGratuit
GOOGLE_CLIENT_ID, GOOGLE_CLIENT_SECRETAvancé : connecteur Google AgendaGratuit
SLACK_CLIENT_ID, SLACK_CLIENT_SECRET, SLACK_SIGNING_SECRETAvancé : connecteur Slack, commande /localtown, synchro du statutGratuit
NOTION_CLIENT_ID, NOTION_CLIENT_SECRETAvancé, facultatif : Notion se connecte en un clic (MCP)Gratuit
GITHUB_CLIENT_ID, GITHUB_CLIENT_SECRETAvancé, facultatif : GitHub se connecte aussi via MCP avec un jetonGratuit
FIGMA_CLIENT_ID, FIGMA_CLIENT_SECRET, FIGMA_WEBHOOK_PASSCODEAvancé : connecteur Figma et ses webhooksGratuit

PostHog, Notion, Linear, GitHub, Sentry, Jira & Confluence, Stripe et Cloudflare n'ont besoin d'aucun secret : ils se connectent en un clic (voir Connexions MCP). L'ancienne clé POSTHOG_PERSONAL_API_KEY reste lue en secours si PostHog n'est pas connecté pour l'espace.

Variables (pas des secrets, dans wrangler.jsonc → vars) : PUBLIC_ORIGIN (adresse publique utilisée dans les liens envoyés par Slack) et DEMO_ENABLED=1 (active la démo de traduction vocale demo/voice.html).

Liaisons déjà déclarées dans wrangler.jsonc : Workers AI (AI, traduction et voix « Éco », Nova-3) et le bucket R2 localtown-media (messages vocaux, enregistrements), à créer une fois :

npx wrangler r2 bucket create localtown-media

Traduction et sous-titres#

Onglet Traduction :

  • Niveau : Éco (Workers AI + voix du navigateur, quasi gratuit) ou Premium (OpenRouter + ElevenLabs).
  • Transcription : navigateur (gratuit) ou Deepgram Nova-3 sur Workers AI (≈ 0,55 $/h, seul l'audio parlé est facturé ; utilisé automatiquement sur Firefox). Quotas en minutes par jour, par personne et pour l'espace.
  • Moteur de traduction : Automatique (OpenRouter si configuré), OpenRouter, Workers AI m2m100 (zéro config), Claude Haiku 4.5 (via OpenRouter). Pour OpenRouter : modèle (défaut google/gemini-2.5-flash-lite), 2 modèles de secours, routage (plus réactif ou débit maximal), et un benchmark en direct pour comparer.
  • Moteur de voix : navigateur, MeloTTS, ElevenLabs (voix par défaut, modèle, voix par personne « Nom = voice id » pour des clones consentis, quota de caractères par jour).

Coûts (par heure de réunion et par langue)#

Le coût ne dépend pas du nombre d'auditeurs : chaque phrase est traduite une seule fois par langue pour tout l'espace, et l'audio est mis en cache.

NiveauTranscriptionTraductionVoixTotal
Éco (défaut)0 $ (navigateur)≈ 0,04 $ (OpenRouter Flash-Lite), ou ≈ 0,01 $ (m2m100 sans clé)0 $ (navigateur)≈ 0,01 à 0,04 $
Éco + MeloTTS0 $≈ 0,04 $≈ 0,01 $≈ 0,05 $
Premium≈ 0,55 $ (Nova-3)≈ 0,04 $≈ 2,2 $ (ElevenLabs Flash v2.5)≈ 2,8 $, ou ≈ 0,6 $ sans voix

Latence Premium de la fin d'une phrase à la première voix traduite : environ 0,8 à 1,3 s. Workers AI inclut 10 000 neurones gratuits par jour. Détails et sources : src/worker/integrations/TRANSLATION.md (prix vérifiés en septembre 2026).

IA (OpenRouter)#

Il n'y a aucune clé Anthropic : tous les appels IA du serveur passent par OpenRouter (OPENROUTER_API_KEY). La pastille 🤖 IA : OpenRouter en haut des réglages le confirme.

Onglet IA :

  • Comptes-rendus et assistant IA : activer ou non ;
  • Modèle : anthropic/claude-sonnet-5.5 par défaut (qualité Claude, via OpenRouter), ou un modèle plus rapide et moins cher comme google/gemini-3.8-flash ; jusqu'à 2 modèles de secours ;
  • Requêtes max par jour pour l'espace (400 par défaut, en plus de 150 par personne) ;
  • Consignes supplémentaires (« Nous sommes ACME, éditeur SaaS. Tutoie les gens. »).

Ce modèle sert aux comptes-rendus (réunions enregistrées, sur toutes les plateformes) et à l'assistant de l'app de bureau quand aucune IA locale n'est branchée. Le panneau d'assistant n'existe pas sur le web ni sur le mobile (voir Assistant IA).

✨ Copilote en direct#

Pendant une réunion, un modèle rapide lit les sous-titres, interroge des serveurs MCP (PostHog, GitHub, Linear, Notion…) quand quelqu'un parle d'un sujet qu'ils connaissent, et affiche une carte d'infos à tout l'appel (voir Réunions). Désactivé par défaut.

Mise en route#

  1. Secrets OPENROUTER_API_KEY et INTG_ENC_KEY.
  2. Dans 🔌 Connecteurs, connecte au moins un service « Pour tout l'espace » (PostHog, Linear, Sentry, Notion…), avec un compte partagé en lecture seule de préférence. Le copilote n'utilise que les connexions de l'espace : ses cartes sont vues par toute la réunion.
  3. Onglet Copilote : coche Activer le copilote en direct, puis Enregistrer. La liste Services utilisés montre les connexions prises en compte.
  4. La zone Pose une question aux MCP essaie une question sans réunion : rien n'est envoyé aux participants.

Réglages#

RéglageDéfautRôle
Modèlegoogle/gemini-3.8-flashRépond avec les outils MCP (routage OpenRouter par latence, raisonnement minimal)
Modèles de secoursgoogle/gemini-3.7-flash, google/gemini-3.5-flash-liteSi le premier est indisponible
Détecteurgoogle/gemini-3.5-flash-liteDécide seulement s'il faut chercher
Recherches max / heure60Budget de l'espace (détections ≤ 8×, actualisations ≤ 6×)
Actualisation live45 s30 à 120 s, seulement tant qu'une carte est ouverte
Mots-clés à surveillervideProjets, sites, produits (« fileworld ») qui déclenchent plus facilement une recherche

Coûts#

La plupart des phrases s'arrêtent à un filtre gratuit (mots-clés, questions, noms de projets). Seules les phrases prometteuses passent au détecteur, et seules celles qu'il valide lancent une recherche.

Poste (réunion d'1 h, 4 personnes)Estimation
Détecteur (≈ 40 appels)≈ 0,01 $
Recherches (≈ 6 cartes, 2 tours d'outils)≈ 0,05 à 0,15 $
Actualisation d'une carte live pendant 30 min≈ 0,02 à 0,10 $
Total≈ 0,05 à 0,30 $ par heure de réunion

Les appels aux serveurs MCP eux-mêmes suivent les limites de chaque outil (PostHog : mêmes quotas que son API). Détails et sources : src/worker/integrations/COPILOT.md.

Sécurité et vie privée#

  • Jetons des serveurs MCP chiffrés (INTG_ENC_KEY), jamais renvoyés au navigateur.
  • URL https:// publiques uniquement (pas d'IP privée, ports 443 / 8443), réponses limitées à 1 Mo, délais courts.
  • Rien n'est stocké à part les cartes (2 h, 12 h si épinglées). Les 90 dernières secondes de sous-titres restent en mémoire, jamais sur disque.
  • Chaque participant voit un bandeau et peut exclure sa voix.

Uptime#

Onglet Uptime : liste de sites à surveiller (nom, URL https://, statut attendu). Vérification chaque minute depuis Cloudflare, historique sur 24 h. Une pastille dans la barre de droite montre l'état, et tout le monde est prévenu quand un service tombe ou revient.

PostHog#

Connecte PostHog « Pour tout l'espace » dans 🔌 Connecteurs : le tableau Analytics et l'écran live passent par le serveur MCP officiel de PostHog (requêtes SQL en lecture seule), sans aucune clé.

Onglet PostHog : ID du projet (épingle la connexion sur ce projet ; sinon, le projet actif du compte connecté), événement « visite », nom du site, entonnoirs de conversion (« Nom = événement A > événement B », 7 derniers jours). La région et la clé POSTHOG_PERSONAL_API_KEY ne servent plus qu'à l'ancien mode, si PostHog n'est pas connecté.

Webhook (GitHub et autres)#

Onglet Webhook : clique sur Enregistrer pour générer l'URL secrète …/api/intg/<espace>/webhook/<secret>, puis 📋 Copier. ♻️ Régénérer le secret invalide l'ancienne URL.

  • GitHub : Settings → Webhooks, type de contenu application/json, évènements Pushes, Pull requests, Pull request reviews, Workflow runs, Check suites, Deployment statuses, Releases. Dans l'onglet GitHub, choisis les dépôts suivis et les animations à afficher. Les pushs, PR, déploiements et CI s'affichent en notification et en animation au-dessus du dev (s'il a relié son compte GitHub).
  • Autre outil : POST {"text": "…", "icon": "🚀", "url": "https://…"} affiche une notification à tout l'espace.

Enregistrements#

Dans ⚙️ Réglages (intégrations) :

  • Enregistrement autorisé : tout le monde (par défaut), seulement les administrateurs, ou personne ;
  • Conservation (jours) : les enregistrements sont supprimés automatiquement après ce délai (90 jours par défaut).

Les fichiers sont stockés dans le bucket R2 localtown-media. Voir Réunions.

🔒 Chiffrement de bout en bout (messages vocaux et enregistrements)#

  • Tout nouveau message vocal ou vidéo, tout nouvel enregistrement, sa transcription et son compte-rendu sont

    chiffrés sur les appareils (schéma lt-e2e-v1 : clés ECDH P-256 par appareil, clé d'identité ECDSA P-256, AES-256-GCM par blocs de 64 Kio). Le serveur refuse les nouveaux envois non chiffrés. Les anciens messages non chiffrés restent lisibles jusqu'à leur expiration.

  • Ni l'admin, ni Cloudflare, ni le Durable Object ne peuvent lire ces contenus. Un admin peut lister et

    supprimer les enregistrements, et régler la durée de conservation, qui s'applique aussi aux données chiffrées.

  • Métadonnées en clair (nécessaires aux droits d'accès, aux quotas et à l'expiration) : identifiants de

    l'expéditeur et du destinataire (ou des participants), salle, dates, durée, taille, identifiants d'appareils et clés publiques.

  • Annuaire de clés : chaque appareil publie ses clés publiques dans l'espace (10 appareils maximum par

    personne). Le serveur pourrait en théorie substituer une clé : c'est pour ça que les utilisateurs peuvent comparer un code de sécurité, et que l'appli avertit quand la clé d'un contact change.

  • Sauvegardes de clés : chiffrées côté client (PBKDF2-SHA256, 600 000 itérations, puis AES-GCM) avant d'être

    stockées. Personne ne peut récupérer une phrase secrète oubliée, pas même un admin.

  • Résumé IA : c'est un choix explicite par enregistrement. La transcription est déchiffrée sur l'appareil,

    envoyée à l'IA (OpenRouter) pour ce seul résumé (rien n'est conservé en clair côté serveur), et le résumé est rechiffré avant d'être enregistré. Les exports Slack et Notion sont eux aussi déclenchés à la main, après confirmation.

Connexions MCP en un clic#

Aucune application à créer chez les outils. LocalTown utilise leur serveur MCP officiel et la spécification d'autorisation MCP (2026-07-28) :

  • Découverte automatique : réponse 401 du serveur, puis métadonnées de la ressource protégée (RFC 9728), puis métadonnées du serveur d'autorisation (RFC 8414).
  • Identité du client : un Client ID Metadata Document publié à <ORIGINE>/api/intg/_mcp/client, ou l'enregistrement dynamique (RFC 7591).
  • Connexion : OAuth 2.1 avec PKCE.
  • Adresse de retour : <ORIGINE>/api/intg/_mcp/callback.

Seul prérequis : le secret INTG_ENC_KEY.

ServiceConnexionRemarque
PostHog, Notion, Linear, Sentry, Jira & Confluence (Atlassian), Stripe, CloudflareEn un clic (OAuth, enregistrement automatique)Stripe : un admin du compte peut devoir autoriser MCP. Atlassian : sites Cloud, limites Rovo.
GitHubJeton « fine-grained » collé par chaque personneGitHub exige une app pré-enregistrée pour son OAuth MCP
  • Portée : chaque connexion est personnelle par défaut. Un admin peut connecter un compte pour tout l'espace : il sert aux TV, au tableau PostHog et au copilote.
  • Serveur personnalisé : 🔌 Connecteurs → + Ajouter un serveur MCP personnalisé (nom, URL https://, OAuth ou jeton).
  • Pas dans le catalogue, car ces serveurs n'acceptent que des clients approuvés, une app propre ou un programme de préversion : Slack, Figma, Vercel, HubSpot, Asana, Google Workspace. Slack, Google Agenda et Figma restent disponibles en OAuth classique ci-dessous.
  • Sécurité :
    • https public uniquement, y compris pour les adresses découvertes ;
    • state à usage unique (10 min), vérification de iss, PKCE S256 ;
    • jetons chiffrés, rafraîchis automatiquement et révoqués à la déconnexion ;
    • jamais envoyés au navigateur ;
    • isolés par personne.

Connecteurs OAuth classiques (avancé)#

Pour Slack (bot, /localtown, synchro du statut), Google Agenda (statut « En réunion », disponibilités, réservation) et Figma, ou pour garder Notion et GitHub en OAuth classique. Ils apparaissent sous Avancé (OAuth classique) dans le panneau des connecteurs.

Chaque personne connecte son propre compte (OAuth 2.0, avec PKCE quand l'outil le permet). Les jetons sont chiffrés et rangés par espace et par personne. Seules les installations « espace » (bot Slack, webhooks GitHub et Figma) sont réservées aux admins.

<ORIGINE> = l'adresse publique de LocalTown (par exemple https://localtown.gregoire-ohanessian.workers.dev, ou http://localhost:8787 en local).

Prérequis communs#

# 32 caractères aléatoires ou plus ; ne JAMAIS la changer ensuite
openssl rand -base64 32 | npx wrangler secret put INTG_ENC_KEY

Et dans wrangler.jsonc, la variable "vars": { "PUBLIC_ORIGIN": "https://ton-domaine" } : l'adresse utilisée dans les liens envoyés hors du navigateur (messages privés Slack).

⚠️ Sans INTG_ENC_KEY, les connecteurs restent « Non configuré ». Si tu la changes, les jetons déjà enregistrés deviennent illisibles et chacun doit se reconnecter.

Adresses de retour, une par outil, communes à tous les espaces :

OutilURI de redirection
Google<ORIGINE>/api/intg/_oauth/callback/google
Slack<ORIGINE>/api/intg/_oauth/callback/slack
Notion<ORIGINE>/api/intg/_oauth/callback/notion
GitHub<ORIGINE>/api/intg/_oauth/callback/github
Figma<ORIGINE>/api/intg/_oauth/callback/figma

📅 Google Agenda#

  1. Google Cloud Console : nouveau projet, puis API et services → Bibliothèque, active Google Calendar API.
  2. Écran de consentement OAuth (« Interne » pour Workspace, sinon « Externe »), champs d'application : openid, email, https://www.googleapis.com/auth/calendar.events, https://www.googleapis.com/auth/calendar.freebusy.
  3. Identifiants → ID client OAuth → Application Web, avec l'URI de redirection Google.
  4. npx wrangler secret put GOOGLE_CLIENT_ID puis GOOGLE_CLIENT_SECRET.

💬 Slack#

  1. api.slack.com/apps → Create New App → From scratch.
  2. OAuth & Permissions : l'URI de redirection Slack ;
    • User Token Scopes (chaque personne) : users.profile:read, users.profile:write ;
    • Bot Token Scopes (installation par un admin) : chat:write, im:write, commands, users:read, channels:read.
  3. Slash Commands : /localtown, Request URL <ORIGINE>/api/intg/_slack/command.
  4. Event Subscriptions : Request URL <ORIGINE>/api/intg/_slack/events, évènement bot user_status_changed.
  5. Secrets : SLACK_CLIENT_ID, SLACK_CLIENT_SECRET, SLACK_SIGNING_SECRET (dans Basic Information).
  6. Dans LocalTown, un admin ouvre 🔌 Connecteurs → Slack → Installer sur l'espace (admin), puis choisit le canal des comptes-rendus.

📝 Notion#

  1. notion.so/profile/integrations → Nouvelle intégration → Publique.
  2. Capacités : lire, insérer et mettre à jour le contenu (pas besoin des e-mails). L'URI de redirection Notion.
  3. Secrets : NOTION_CLIENT_ID, NOTION_CLIENT_SECRET.
  4. Chacun choisit, pendant l'autorisation, les pages partagées avec LocalTown, puis sa base des comptes-rendus dans 🔌 Connecteurs. La base doit avoir une propriété Titre (idéalement une Date).

🐙 GitHub#

  1. Settings → Developer settings → OAuth Apps → New OAuth App (compte ou organisation). Homepage <ORIGINE>, callback = l'URI GitHub.
  2. Scopes : read:user, plus repo seulement si la personne coche « Inclure les dépôts privés ».
  3. Secrets : GITHUB_CLIENT_ID, GITHUB_CLIENT_SECRET.
  4. Animations et lampe CI : ajoute le webhook de l'espace (voir Webhook) avec les évènements Pushes, Pull requests, Pull request reviews, Workflow runs, Check suites, Deployment statuses, Releases. Les évènements et dépôts suivis se règlent dans ⚙️ Intégrations → GitHub.

🎨 Figma#

  1. figma.com/developers/apps → Create a new app. Callback = l'URI Figma, scopes current_user:read, file_metadata:read.
  2. Secrets : FIGMA_CLIENT_ID, FIGMA_CLIENT_SECRET.
  3. Pour l'activité « 🎨 édite … » : crée un webhook Figma v2 d'équipe (FILE_VERSION_UPDATE, FILE_COMMENT) vers <ORIGINE>/api/intg/_figma/webhook, avec un code secret enregistré par npx wrangler secret put FIGMA_WEBHOOK_PASSCODE.

Sécurité#

  • Jetons chiffrés au repos (AES-GCM, clé dérivée de INTG_ENC_KEY).
  • Chaque appel est authentifié par le jeton de la personne : personne ne peut utiliser les accès d'un autre.
  • Slack : signature vérifiée (fenêtre de 5 min). Figma : code secret. GitHub : secret dans l'URL du webhook.
  • Déconnecter révoque le jeton chez l'outil quand c'est possible (Google, Slack, GitHub), puis l'efface.

Référence technique complète : src/worker/integrations/CONNECTORS.md.

Proposer une modification de cette page