Skip to main content

Architettura della Piattaforma

Switchbord è distribuito come applicazione Next.js multi-tenant su Vercel, supportata da Supabase per persistenza, autenticazione e realtime, con un worker ospitato su Railway per l’elaborazione in background. Non esiste un servizio control-plane separato — quel percorso architetturale è stato ritirato e tutte le responsabilità di runtime sono state consolidate.

Topologia

  • apps/app: prodotto per l’operatore — inbox, contatti, template, campagne, Margaret AI, impostazioni. Distribuito su Vercel.
  • apps/web: sito marketing, flussi QR/opt-in, landing page con accesso controllato. Distribuito su Vercel.
  • apps/api: superficie API Next.js per l’ingress dei webhook Meta, API REST pubblica v1 (specifica OpenAPI su /spec), endpoint di compatibilità e route di health/status. Distribuito su Vercel.
  • apps/docs: documentazione basata su Mintlify. Distribuito su Mintlify.
  • apps/worker: elaborazione delle code, retry, scheduler delle campagne, dispatch dei messaggi, strumenti di replay. Distribuito su Railway.
  • Supabase: Postgres, Auth, Storage, Realtime, Vault. Fonte unica di verità.
Il servizio apps/control-plane è stato rimosso. Tutto il lavoro control-plane orientato ai webhook ora viene eseguito all’interno di apps/api e apps/worker. Eventuali riferimenti locali alla porta 4000 o a apps/control-plane/.env.example sono artefatti legacy.

Percorsi Core del Runtime

  1. Webhook in entrata — Meta invia un webhook a apps/api → firma verificata con crypto.timingSafeEqual → busta raw memorizzata in webhook_events → Supabase notifica apps/worker → il worker instrada verso il processore di messaggi, stato, template o journey.
  2. Invio in uscita — L’operatore o un’automazione crea un intent di invio → Supabase registra su outbox_jobsapps/worker pianifica in base ai limiti di throughput/coppia → la risposta di Meta viene registrata → i webhook di stato aggiornano il ledger.
  3. Broadcast — Viene creato uno snapshot dell’audience → il worker distribuisce gli outbox job → Supabase Realtime spinge l’avanzamento della campagna alla dashboard dell’operatore.
  4. Margaret AI — L’operatore attiva la bozza di risposta AI → apps/app chiama /api/ai-assistant → il provider LLM del workspace viene risolto da llm_provider_configs → i dati PII vengono pseudonimizzati prima di qualsiasi prompt → la risposta viene de-pseudonimizzata → la bozza viene mostrata nell’inbox. L’esecuzione tramite agent (BORD-140–143) aggiunge l’uso di strumenti (tool-use) al di sopra.

Modello di Workspace Multi-Tenant

Ogni tenant è un workspace isolato. Le garanzie di isolamento fondamentali:
  • Il contesto del workspace viene risolto lato server da workspace_members — non da variabili d’ambiente o header forniti dal client.
  • Tutte le query sui dati sono ambitate (scoped) da workspace_id derivato da tale risoluzione.
  • Il dispatch dei messaggi legge le credenziali Meta dai segreti Vault del workspace proprietario — nessuna fuoriuscita di credenziali tra workspace.
  • Quattro ruoli RBAC applicati su ogni route: owner, admin, developer, operator.
Vedi Multi-Tenancy e Isolamento dei Workspace per il modello di sicurezza completo.

Livello Margaret AI

Il livello AI introduce tre nuove preoccupazioni di runtime:
  • Configurazioni provider LLM — record posseduti dal workspace in llm_provider_configs che puntano a OpenAI, Anthropic, OpenRouter, Ollama o vLLM. Le chiavi API sono memorizzate in Supabase Vault tramite workspace_secret_bindings.
  • Agent AI — la tabella ai_agents definisce persona, modello, permessi degli strumenti e impostazioni di pseudonimizzazione PII per workspace.
  • Thread AIai_threads e ai_thread_messages mantengono il contesto di conversazione per le risposte di Margaret. ai_agent_executions registra le esecuzioni di tool-use per la tracciabilità (auditability).
Il registro dei consensi (BORD-193) fornisce un record durevole e verificabile di ogni evento di opt-in e opt-out per contatto:
  • Tabella consent_events — log append-only delle transizioni di consenso (opt-in / opt-out / revocato). Un trigger AFTER INSERT su questa tabella denormalizza lo stato più recente in contacts.consent_state per letture rapide.
  • Rilevamento delle parole chiave STOP / STARTpackages/whatsapp analizza i messaggi in entrata per le parole chiave localizzate di opt-out (STOP, BLOQUEAR, FERMA, PARAR) e opt-in (START, INICIO, INIZIO, COMEÇAR) in inglese, italiano, portoghese e spagnolo.
  • Gate opt-out del dispatch di campagna — il motore di broadcast verifica contacts.consent_state prima di accodare qualsiasi outbox job. I contatti in stato opted_out o revoked vengono silenziosamente saltati.
  • Endpoint RESTGET /api/v1/contacts/:id/consent restituisce lo stato attuale e la cronologia degli eventi; POST /api/v1/contacts/:id/consent registra una transizione di consenso manuale (solo owner/admin).

Command Palette

La command palette (BORD-204) è una superficie ⌘K per la navigazione, la ricerca e le azioni nel prodotto per l’operatore:
  • command-palette.tsx — il contenitore della palette, attivato da ⌘K / Ctrl+K. Renderizza un elenco di comandi ricercabile raggruppato per categoria.
  • command-palette-provider.tsx — contesto React che aggrega i comandi disponibili da ogni modulo (inbox, contatti, campagne, template, journey, impostazioni) e gestisce lo stato apertura/chiusura.
  • command-palette-hint.tsx — badge di suggerimento inline mostrato nella sidebar e nelle intestazioni di pagina per scoprire la scorciatoia.
La palette è estensibile: qualsiasi modulo può registrare comandi tramite il hook registerCommands del provider.

Editor Visivo dei Journey

Un canvas React Flow su /journeys/[id] per costruire automazioni multi-step in modo visivo:
  • 9 tipi di nodo — Trigger, Condition, Wait, Send Template, Update Attribute, Add/Remove Tag, Outbound Webhook, AI Agent Step, e Exit.
  • Validazione — l’editor valida i campi obbligatori, la connettività degli edge e la rilevazione dei cicli prima della pubblicazione. Gli errori vengono mostrati inline su ogni nodo.
  • Pipeline di pubblicazione — i grafi validati vengono serializzati nella tabella journeys come JSON versionato. Una mutation publish crea uno snapshot immutabile e attiva il journey per l’esecuzione live da parte di apps/worker.

Costruttore Visivo di Template

Un builder a 3 pannelli su /templates/new per comporre template di messaggi WhatsApp:
  • 7 editor — Header, Body, Footer, Buttons, Examples, Language e Category.
  • Colonna parameter_format — memorizzata su message_templates per dichiarare il tipo e l’ordine previsti delle variabili del template.
  • Pipeline di invio a Meta — il builder invia (POST) il template composto alla Meta Business API e traccia lo stato di approvazione tramite i webhook di stato dei template.
  • Renderer a cornice telefono — un componente di anteprima live rende il template come apparirebbe su un dispositivo, con sostituzione dei placeholder per le variabili.

Agent con Auto-Trigger

L’agent con auto-trigger (BORD-192) estende Margaret AI per redigere automaticamente risposte sui messaggi WhatsApp in entrata:
  • Trigger di esecuzione dell’agent — quando arriva un messaggio in entrata e il workspace ha configurato un agent con auto-trigger, agent.run viene invocato automaticamente dal worker.
  • API di accettazione/rifiuto della bozzaPOST /api/v1/contacts/:id/drafts/:draftId/accept e POST /api/v1/contacts/:id/drafts/:draftId/reject permettono agli operatori di approvare o scartare le bozze generate dall’AI.
  • Banner della bozza nell’inbox — un banner prominente nella vista della conversazione avvisa gli operatori quando una bozza è in attesa, con azioni di accettazione/rifiuto a un clic.

Storage degli Asset

Lo storage degli asset (BORD-187) fornisce upload di file ambitati per workspace per template, journey e asset di knowledge base:
  • Tabella asset_files — registra i metadati del file (nome, tipo MIME, dimensione, ambito workspace) e punta all’oggetto memorizzato.
  • Pipeline compatibile con S3 — gli upload passano attraverso una pipeline con URL prefirmato verso qualsiasi object store compatibile con S3. Il worker recupera gli oggetti al momento del dispatch per gli invii di media.
  • Isolamento del workspace — ogni file è ambitato da workspace_id; l’accesso cross-workspace viene rifiutato a livello di API.

Alert sull’Account

Gli alert sull’account (BORD-189) mostrano agli operatori i problemi a livello di account Meta:
  • Handler del webhookapps/api elabora gli eventi webhook account_alerts di Meta e li memorizza in account_alert_events.
  • Pannello UI per l’operatore — un pannello dedicato nelle impostazioni mostra gli alert attivi (ad es. violazioni delle policy, avvisi sui rate limit, scadenza delle credenziali) con gravità e passaggi di risoluzione.

Log di Audit

I log di audit (BORD-158) registrano le azioni degli operatori per conformità e analisi forense:
  • Tabella audit_logs — log append-only ambitato per workspace di attore, azione, risorsa di destinazione e payload diff.
  • writeAuditLog() — un helper lato server che ogni route di mutazione chiama prima di eseguire il commit. Garantisce una struttura coerente e previene omissioni accidentali.

Conservazione dei Dati GDPR

La conservazione dei dati GDPR (BORD-165 / BORD-167) applica limiti di conservazione per workspace:
  • data_retention_days — un’impostazione a livello di workspace (default 365). Controlla per quanto tempo vengono conservate le buste dei webhook, il contenuto dei messaggi e gli eventi di consenso.
  • Job retention_sweep — un job del worker pianificato che elimina i record più vecchi della finestra di conservazione del workspace. Viene eseguito giornalmente; registra le metriche di sweep in audit_logs.

Generazione delle Chiavi API

La generazione delle chiavi API (BORD-178) consente ai proprietari del workspace di fornire chiavi API di lunga durata:
  • Chiavi con prefisso swb_ — generate lato server con un segreto casuale crittograficamente sicuro di 32 byte. Il prefisso consente un’identificazione visiva rapida e il rilevamento programmatico nei log.
  • Metadati della chiave — memorizzati in api_keys con timestamp di creazione, timestamp di ultimo utilizzo e descrizione opzionale. Le chiavi sono sottoposte a hash a riposo; il segreto completo viene mostrato solo una volta alla creazione.

Wizard Guidato

Il wizard guidato (BORD-194) fornisce un flusso di onboarding dal primo avvio al primo messaggio:
  • Sequenza di step — collega il numero WhatsApp → configura il provider LLM → crea il primo template → invia il primo messaggio.
  • Tracciamento dell’avanzamento — memorizzato in workspace_onboarding_state. Il wizard avanza automaticamente ed è ignorabile dopo il completamento.
  • Punto di ingresso — i workspace appena creati vengono reindirizzati a /welcome al primo login. Il wizard è anche accessibile dalle Impostazioni.

Primitive del Design System

Nuove primitive del design system rilasciate in packages/design-system:
  • Design token — token semantici di colore, spaziatura e tipografia in tokens.css, utilizzati da tutti i componenti shadcn/ui.
  • Motion — utility di transizione e animazione coerenti in motion.ts (durate, easing, preset di enter/exit).
  • Skeleton — componente Skeleton con animazione pulse, utilizzato come placeholder di caricamento in tutto il prodotto per l’operatore.

Aggiornamenti al Brand

  • Wordmark trasparente — il logo della sidebar espansa ora utilizza un wordmark SVG con sfondo trasparente per un rendering pulito su qualsiasi superficie.
  • Favicon con sfondo nerofavicon.ico aggiornato a una variante con sfondo nero per una maggiore visibilità nelle tab del browser.

Principi di Dati e Sicurezza

  • Ogni busta di webhook è immutabile; il corpo raw + i metadati vengono conservati con controlli di conservazione configurabili.
  • La cronologia di consegna è append-only (outbox_jobs, message_status_events) — non viene mai sovrascritta.
  • RBAC, feature flag e segreti del provider rimangono solo lato server.
  • Topic Broadcast privati di Supabase Realtime alimentano i feed realtime dell’operatore; nessun broadcast di Postgres Changes per evitare problemi di scalabilità.
  • Log di audit su ogni azione dell’operatore e rotazione delle credenziali.
  • Il registro dei consensi applica l’opt-out prima di qualsiasi dispatch di campagna o automazione.
  • Gli sweep di conservazione dei dati applicano le tempistiche di eliminazione GDPR per workspace.
Vedi Panoramica sulla Sicurezza per lo stato completo di implementazione dei controlli.

UI Operatore — Sidebar e Navigazione

L’UI dell’operatore (apps/app) utilizza una sidebar costruita sulle primitive Sidebar di shadcn/ui.

Componente

  • File: apps/app/components/operator-sidebar.tsx (~165 righe)
  • Pattern: collapsible='icon' — si collassa in una barra solo icone; si espande al passaggio del mouse o al toggle. L’interfaccia delle prop è stabile.
  • Layout: Ogni pagina che necessita della sidebar avvolge il proprio contenuto con SidebarProvider.

Struttura di navigazione

  • Sezione superiore (nav piatta): Inbox / Contatti / Broadcast / Template / Operazioni
  • Sezione inferiore (footer): Impostazioni / Documentazione / Account utente

Theming

La sidebar utilizza i valori predefiniti standard delle variabili CSS chiare di shadcn — non c’è un tema scuro personalizzato né className='dark' applicato all’elemento sidebar. Variabili rilevanti (definite sotto :root in packages/design-system/styles/globals.css):
  • --sidebar: sfondo quasi bianco
  • --sidebar-foreground: testo quasi nero
Il tema scuro personalizzato quasi-nero della sidebar precedente alla PR #270 è stato rimosso. La sidebar ora eredita dai token standard del design system chiaro del workspace.
  • Espanso: wordmark completo
  • Collassato: solo il marchio icona

Monitoraggio + Deployment

  • Endpoint di health: /health, /ready, /internal/runtime.
  • Endpoint operativi: /internal/webhooks, /internal/webhook-rejections, /internal/webhooks/:id/replay.
  • Specifica OpenAPI + explorer Scalar: /spec.
  • Distribuisci apps/app, apps/web, apps/api e apps/docs su Vercel/Mintlify. Distribuisci apps/worker su Railway. Tutte le superfici condividono lo stesso progetto Supabase.
  • La CI valida build, migrazioni, lint della documentazione e scansioni dei segreti. Vedi CI/CD.

Leggi anche