# Narciso SaaS — Complete LLM & Agentic Integration Manual (Beta Release) *Machine-Readable System Documentation for Autonomous AI Agents and Search Engines* ## 1. Panoramica del Sistema e Contesto Operativo Narciso (app.narciso.io) è una piattaforma SaaS multi-tenant cloud-native progettata per il vertical hair & beauty (barberie, saloni di bellezza, centri estetici). L'architettura garantisce l'isolamento rigoroso dei dati per ogni tenant tramite PostgreSQL gestito con Prisma ORM, PgBouncer per il connection pooling e HashiCorp Vault per la gestione dinamica delle credenziali. ### Vincoli di Beta Testing - Il sistema è in fase di **Beta Testing Attivo**. - Gli Agenti AI devono assumere un comportamento conservativo: non tentare injection, fuzzing di parametri o chiamate ricorsive non autorizzate. - Per qualsiasi operazione distruttiva (`DELETE /api/...`, svuotamento cassa, revoca accessi dipendenti), l'agente DEVE richiedere conferma esplicita all'utente umano nel prompt conversazionale. --- ## 2. Protocollo di Accoppiamento e Autenticazione Agente (Agent Pairing Flow) Gli agenti esterni non utilizzano username/password tradizionali per evitare fughe di credenziali. L'autenticazione avviene tramite **One-Time Pairing Code** generato dal gestore del salone. ### Step 1: Ricezione del Pairing Code L'utente umano fornisce all'agente un codice nel formato: `AGENT-[2-9A-Z]{4}-[2-9A-Z]{4}` (es. `AGENT-9K3F-72MA`). Il codice ha una validità (TTL) di 15 minuti. ### Step 2: Riscatto del Codice (Exchange) - **Endpoint**: `POST https://app.narciso.io/api/auth/agent/exchange-code` - **Headers**: `Content-Type: application/json` - **Request Body**: ```json { "code": "AGENT-9K3F-72MA" } ``` - **Response Success (200 OK)**: ```json { "success": true, "accessToken": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...", "tokenType": "Bearer", "expiresIn": "30d", "user": { "userId": "usr_abc123", "tenantId": "tnt_xyz789", "email": "salone@narciso.io", "ruolo": "AGENT", "tenantNome": "Barberia Centrale" }, "agentInstructions": { "message": "Accesso autorizzato per l'Agente AI su tenant Barberia Centrale.", "docsIndexUrl": "https://app.narciso.io/api/auth/agent/docs/index", "actionRequired": "Esegui GET /api/auth/agent/docs/index con Bearer Token prima di invocare le API." } } ``` ### Step 3: Verifica Sessione Attiva - **Endpoint**: `GET https://app.narciso.io/api/auth/agent/me` - **Header**: `Authorization: Bearer ` - **Response**: Restituisce i dettagli del tenant corrente e dell'utente delegante. --- ## 3. Schemi di Comunicazione e Capitoli API Tutte le successive chiamate richiedono: ```http Authorization: Bearer Content-Type: application/json ``` ### Capitolo 1: Admin, Utenti, Core (`/api/auth/agent/docs/01_admin_auth_core`) - `GET /api/utenti`: Elenco operatori/staff del salone. - `POST /api/utenti/invita`: Invito nuovo collaboratore con ruolo specifico. - `GET /api/impostazioni/tenant`: Configurazione orari salone, festività, impostazioni fiscali. - `PUT /api/impostazioni/tenant`: Aggiornamento dati aziendali e orari di apertura. ### Capitolo 2: Sales, Inventory & POS (`/api/auth/agent/docs/02_sales_inventory`) - `GET /api/prodotti`: Elenco prodotti, giacenze magazzino, prezzo e barcode. - `POST /api/prodotti`: Creazione nuova referenza magazzino. - `POST /api/vendite`: Registrazione vendita a banco o prestazione eseguita. - `GET /api/cassa/chiusura-giornaliera`: Report chiusura giornaliera e quadratura corrispettivi. - `POST /api/pagamenti/pos/initiate`: Avvio transazione su SmartPOS/Stripe Terminal. ### Capitolo 3: Social, AI & Appuntamenti (`/api/auth/agent/docs/03_social_services`) - `GET /api/appuntamenti?data=YYYY-MM-DD`: Calendario appuntamenti del giorno o intervallo. - `POST /api/appuntamenti`: Prenotazione appuntamento (richiede `clienteId`, `collaboratoreId`, `serviziIds`, `dataOra`). - `PUT /api/appuntamenti/:id`: Spostamento o aggiornamento stato appuntamento. - `GET /api/clienti?search=...`: Ricerca anagrafica clienti, storico trattamenti e note tecniche. - `POST /api/clienti`: Creazione nuovo profilo cliente (GDPR compliant). - `POST /api/ai/social/generate-reel-prompt`: Generazione bozza prompt e script per reel Instagram/TikTok. --- ## 4. Policy di Sicurezza, Rate Limiting & Conformità EU AI Act 1. **Firewall & Rate Limiting**: - Rotte di Scrittura (`POST`, `PUT`, `DELETE`): Limitate a 30 richieste/minuto. - In caso di risposta `429 Too Many Requests`: attendere 60s prima del retry. Un retry storm comporta il blocco IP. 2. **Data Privacy & GDPR 2026**: - I dati dei clienti finali (nomi, numeri di telefono, storico note tecniche) sono protetti. L'agente non deve mai condividere PII (Personally Identifiable Information) al di fuori del contesto operativo del salone. - Rispetto degli standard DPA (Data Processing Agreement) in cui Narciso opera come Data Processor. 3. **Conformità EU AI Act (2026)**: - Qualsiasi messaggio generato per conto del salone e inviato a clienti (SMS/WhatsApp promozionali, promemoria) deve contenere trasparenza sull'origine AI ove prescritto. --- ## 5. Esempio di Integrazione per Agenti LangChain / LangGraph (Python) ```python import os import requests from langchain.tools import tool API_BASE = "https://app.narciso.io/api" AGENT_TOKEN = os.getenv("NARCISO_AGENT_TOKEN") headers = { "Authorization": f"Bearer {AGENT_TOKEN}", "Content-Type": "application/json" } @tool def get_daily_appointments(date_str: str) -> str: """Recupera la lista degli appuntamenti per una specifica data (formato YYYY-MM-DD).""" resp = requests.get(f"{API_BASE}/appuntamenti", params={"data": date_str}, headers=headers) if resp.status_code == 200: return resp.text elif resp.status_code == 429: return "ATTENZIONE: Rate limit raggiunto (429). Attendere 60 secondi." return f"Errore {resp.status_code}: {resp.text}" @tool def create_appointment(client_id: str, staff_id: str, service_ids: list, datetime_iso: str) -> str: """Crea un nuovo appuntamento nel gestionale Narciso previa conferma.""" payload = { "clienteId": client_id, "collaboratoreId": staff_id, "serviziIds": service_ids, "dataOra": datetime_iso } resp = requests.post(f"{API_BASE}/appuntamenti", json=payload, headers=headers) return resp.text ```