Un unico codebase generato dall'AI per Web, Mobile e API
Scopri come un singolo codebase generato dall'AI può alimentare web app, app mobile e API con logica condivisa, modelli dati coerenti e rilasci più sicuri.

Cosa significa un singolo codebase generato dall'AI
“Un codebase” raramente significa una sola UI che gira ovunque. In pratica significa di solito un repository e un insieme condiviso di regole—con superfici di consegna separate (web app, app mobile, API) che dipendono tutte dalle stesse decisioni di business sottostanti.
Logica condivisa vs. UI condivisa
Un modello mentale utile è condividere le parti che non dovrebbero mai contraddirsi:
- Regole di dominio: calcoli, controlli di idoneità, pricing, workflow, invarianti.
- Casi d'uso: “create order,” “cancel subscription,” “issue refund,” ecc.
- Contratti di dati: forme request/response, regole di validazione, codici di errore.
Nel frattempo, di solito non condividi l'intero layer UI. Web e mobile hanno pattern di navigazione diversi, aspettative di accessibilità, vincoli di performance e capacità di piattaforma differenti. Condividere la UI può essere vantaggioso in alcuni casi, ma non è la definizione di “un codebase”.
Cosa cambia con l'AI (e cosa no)
Il codice generato dall'AI può velocizzare enormemente:
- lo scaffold di progetti (cartelle, script di build, componenti di base)
- la generazione di endpoint CRUD e dei client
- la creazione di test e fixture a partire da esempi
Ma l'AI non produce automaticamente un'architettura coerente. Senza confini chiari, tende a duplicare la logica nelle app, mescolare le responsabilità (UI che chiama direttamente codice del DB) e creare convalide “quasi identiche” in più posti. Il vantaggio reale arriva dal definire prima la struttura—poi usare l'AI per riempire le parti ripetitive.
Risultati da cercare
Un codebase assistito dall'AI ha successo quando offre:
- Coerenza: web, mobile e API applicano le stesse regole.
- Velocità: le nuove funzionalità si sviluppano una volta e poi si propagano ovunque.
- Manutenibilità: le modifiche sono localizzate, revisionate, testate e rilasciate in modo prevedibile.
Obiettivi e vincoli per la delivery Web, Mobile e API
Un singolo codebase funziona solo quando si è chiari su cosa deve ottenere—e su cosa non deve cercare di standardizzare. Web, mobile e API servono pubblici e pattern di utilizzo diversi, anche quando condividono le stesse regole di business.
Chi servi (e come)
La maggior parte dei prodotti ha almeno tre “porte d'ingresso”:
- Utenti web (clienti, amministratori, team di supporto) che si aspettano navigazione veloce, accessibilità e aggiornamenti semplici.
- Utenti mobile che si aspettano interazioni native, supporto per connettività intermittente e uso efficiente di batteria/rete.
- Integrazioni di terze parti (partner, sistemi interni, tool di automazione) che dipendono da API stabili, contratti chiari e gestione prevedibile degli errori.
L'obiettivo è coerenza nel comportamento (regole, permessi, calcoli)—non esperienze identiche.
Non-obiettivi: non forzare UX identiche
Un fallimento comune è trattare “single codebase” come “single UI.” Questo spesso produce una app mobile dall'aspetto web o una web app dal comportamento mobile—entrambi frustranti.
Invece, punta a:
- Logica di dominio e validazione condivise
- Modelli di dati e contratti API condivisi
- Design di presentazione e interazione specifici per piattaforma
Vincoli chiave da progettare presto
Modalità offline: il mobile spesso ha bisogno di accesso in lettura (e talvolta scrittura) senza rete. Questo implica storage locale, strategie di sync, gestione dei conflitti e regole chiare su quale sia la “fonte di verità”.
Performance: il web guarda al bundle size e al time-to-interactive; il mobile allo startup time e all'efficienza di rete; le API a latenza e throughput. Condividere codice non dovrebbe significare spedire moduli inutili a ogni client.
Sicurezza e compliance: autenticazione, autorizzazione, audit trail, crittografia e retention dei dati devono essere coerenti su tutte le superfici. Se operi in spazi regolamentati, integra requisiti come logging, consenso e accesso minimo privilegiato fin dall'inizio—non come toppe.
Architettura di riferimento: livelli e responsabilità
Un singolo codebase funziona meglio quando è organizzato in livelli chiari con responsabilità nette. Questa struttura rende anche il codice generato dall'AI più semplice da revisionare, testare e sostituire senza rompere parti non correlate.
Flusso ad alto livello
Ecco la forma base su cui si allineano la maggior parte dei team:
Clients (Web / Mobile / Partners)
↓
API Layer
↓
Domain Layer
↓
Data Sources (DB / Cache / External APIs)
L'idea chiave: interfacce utente e dettagli di trasporto stanno ai margini, mentre le regole di business restano al centro.
Cosa viene condiviso
Il “nucleo condivisibile” è tutto ciò che dovrebbe comportarsi allo stesso modo ovunque:
- Domain (logica di business): regole di pricing, controlli di idoneità, transizioni di stato degli ordini, ecc.
- Validazione: regole di input e messaggi di errore mappati su codici di errore coerenti.
- Networking + schemi: tipi request/response, serializzazione e test di contratto.
Quando l'AI genera nuove funzionalità, il miglior risultato è: aggiorna le regole di dominio una sola volta e tutti i client ne beneficiano automaticamente.
Cosa dovrebbe rimanere diverso
Alcuni codici sono costosi (o rischiosi) da forzare in un'astrazione condivisa:
- Componenti UI: design system web vs. controlli nativi.
- Navigazione e flussi utente: routing del browser vs. stack di navigazione mobile.
- Capacità del dispositivo: notifiche push, biometrici, fotocamera, storage offline.
Una regola pratica: se l'utente può vederlo o il sistema operativo può romperlo, mantienilo specifico dell'app. Se è una decisione di business, mantienila nel dominio.
Responsabilità per livello
- API layer: autenticazione, rate limits, mappatura HTTP/GraphQL ai comandi di dominio.
- Domain layer: regole pure e casi d'uso, dipendenze minime.
- Data sources: database e servizi terzi dietro interfacce così le implementazioni possono cambiare senza riscrivere la logica di business.
Shared Domain Layer (Logica di Business)
Lo strato di dominio condiviso è la parte del codebase che dovrebbe sembrare “noiosa” nel senso migliore: prevedibile, testabile e riutilizzabile ovunque. Se l'AI ti aiuta a generare il sistema, questo layer è dove ancorare il significato del progetto—così schermate web, flussi mobile e endpoint API riflettono le stesse regole.
Inizia con nomi e verbi
Definisci i concetti core del tuo prodotto come entità (oggetti con identità nel tempo, come Account, Order, Subscription) e value objects (definiti dal loro valore, come Money, EmailAddress, DateRange). Poi cattura il comportamento come use case (a volte chiamati application services): “Create order,” “Cancel subscription,” “Change email.”
Questa struttura mantiene il dominio comprensibile anche ai non specialisti: i sostantivi descrivono cosa esiste, i verbi cosa fa il sistema.
Mantieni le regole di business agnostiche rispetto alla UI
La logica di business non dovrebbe sapere se viene attivata da un tap, dall'invio di un form web o da una richiesta API. Praticamente, questo significa:
- Nessuna importazione di framework (niente controller web, view mobile o annotazioni ORM nel codice di dominio)
- Nessuna stringa UI (meglio codici di errore o chiavi che messaggi hard-coded)
- Nessuna assunzione di rete (il dominio non dovrebbe “chiamare l'API”; dovrebbe esprimere regole)
Quando l'AI genera codice, questa separazione è facile da perdere—i modelli vengono riempiti di preoccupazioni UI. Trattalo come un trigger di refactor, non come preferenza.
Un set unico di regole di validazione ovunque
La validazione è dove i prodotti spesso divergono: il web permette qualcosa che l'API rifiuta, o il mobile valida in modo diverso. Metti la validazione coerente nel dominio (o in un modulo di validazione condiviso) così tutte le superfici applicano le stesse regole.
Esempi:
EmailAddressvalida il formato una volta sola, riutilizzato su web/mobile/APIMoneyimpedisce totali negativi, indipendentemente da dove provenga il valore- I casi d'uso fanno rispettare regole cross-field (es. “end date deve essere dopo start date”)
Se fatto bene, l'API diventa un traduttore e web/mobile diventano presenter—mentre il dominio resta la singola fonte di verità.
API Layer: contratti che guidano tutto il resto
L'API layer è il “volto pubblico” del tuo sistema—e in un codebase unificato generato dall'AI, dovrebbe essere la parte che ancora ancorata a tutto il resto. Se il contratto è chiaro, la web app, la mobile app e persino i servizi interni possono essere generati e verificati rispetto alla stessa fonte di verità.
Parti dal contratto API prima di tutto
Definisci il contratto prima di generare handler o wiring UI:
- Endpoint e risorse: sostantivi coerenti (es.
/users,/orders/{id}), filtraggio e sorting prevedibili. - Errori: forma stabile di errore (code, message, details), con uso documentato degli status HTTP.
- Paginazione: scegli un approccio (cursor-based è spesso più facile da evolvere) e standardizza i campi di risposta.
- Versioning: decidi presto (path tipo
/v1/...o header-based) e documenta le regole di deprecazione.
Genera tipi e client da uno schema
Usa OpenAPI (o uno strumento schema-first come GraphQL SDL) come artefatto canonico. Da lì genera:
- server stubs (route, scaffolding di validazione)
- client tipizzati per web e mobile
- modelli request/response condivisi che riducono la deriva
Questo è importante per il codice generato dall'AI: il modello può creare molto codice rapidamente, ma lo schema lo mantiene allineato.
Regole di coerenza che prevengono rotture sottili
Imposta alcuni non-negotiabili:
- Naming:
snake_caseocamelCase, non entrambi; corrispondenza tra JSON e tipi generati. - Status codes: 200/201/204 per successi, 400 per validazione, 401/403 per auth, 409 per conflitti.
- Idempotenza: richiedi un
Idempotency-Keyper operazioni rischiose (pagamenti, creazione ordine) e definisci il comportamento di retry.
Tratta il contratto API come un prodotto. Quando è stabile, tutto il resto diventa più facile da generare, testare e distribuire.
Web App: integrare la logica condivisa senza accoppiamento
Una web app trae grande beneficio dalla logica di business condivisa—e soffre quando quella logica si intreccia con le preoccupazioni UI. La chiave è trattare lo strato di dominio condiviso come un motore “headless”: conosce regole, validazioni e workflow, ma nulla su componenti, route o API del browser.
Scelte di rendering: SSR vs CSR (e perché conta)
Se usi SSR (server-side rendering), il codice condiviso deve essere sicuro da eseguire sul server: niente window, document o chiamate allo storage del browser direttamente. È una buona costrizione: spinge a tenere il comportamento dipendente dal browser in un sottile web adapter.
Con CSR (client-side rendering) hai più libertà, ma la stessa disciplina ripaga. I progetti CSR-only spesso “accidentalmente” importano codice UI nei moduli di dominio perché tutto gira nel browser—fino a quando non aggiungi SSR, edge rendering o test che girano in Node.
Una regola pratica: i moduli condivisi devono essere deterministici e agnostici all'ambiente; qualsiasi cosa tocchi cookie, localStorage o URL appartiene al layer web.
Confini di stato: stato di dominio vs stato UI
La logica condivisa può esporre domain state (es. totali ordine, idoneità, flag derivati) tramite oggetti semplici e funzioni pure. La web app dovrebbe possedere lo stato UI: spinner di caricamento, focus dei form, animazioni ottimistiche, visibilità modali.
Questo mantiene flessibile la gestione dello stato in React/Vue: puoi cambiare librerie senza riscrivere le regole di business.
Preoccupazioni specifiche del web da isolare
Il layer web dovrebbe gestire:
- Accessibilità (markup semantico, navigazione da tastiera, ARIA)
- Routing (struttura URL, deep link, redirect server)
- Storage del browser (cookie/session,
localStorage, caching)
Pensa alla web app come a un adattatore che traduce le interazioni utente in comandi di dominio—e traduce gli esiti del dominio in schermate accessibili.
Mobile App: logica condivisa con capacità native
Un'app mobile beneficia soprattutto di uno strato di dominio condiviso: le regole per pricing, idoneità, validazione e workflow devono comportarsi come su web e API. La UI mobile diventa una “shell” attorno a quella logica condivisa—ottimizzata per touch, connettività intermittente e feature del dispositivo.
Pattern di piattaforma da prevedere
Anche con la logica condivisa, il mobile ha pattern che raramente si mappano 1:1 al web:
- Navigazione: modella lo stato di navigazione nell'app layer (schermate, tab, modali), mantenendo le decisioni di dominio (es. “l'utente deve verificare l'email prima del checkout”) nel codice condiviso.
- Task in background: tratta sync, upload e refresh come job espliciti con limiti di tempo e riavviabilità.
- Notifiche push: parse del payload in app, poi passa alla logica condivisa per decidere l'azione successiva.
- Deep link: instrada link nell'app layer, ma usa la logica condivisa per validare permessi e recuperare dati richiesti.
Offline-first: caching, sync e strategia di conflitto
Se prevedi uso mobile reale, assumi offline:
- Cache dei modelli di lettura localmente (key-value o SQLite) con una politica di staleness chiara.
- Metti in coda le scritture come intenti/eventi (es. “create order draft”), poi sincronizza quando sei online.
- Definisci regole di conflitto in anticipo (last-write-wins, merge server-authoritative o risoluzione utente).
- Implementa retry con backoff e idempotency keys così l'API può accettare duplicati in sicurezza.
Preoccupazioni specifiche del mobile
- Dimensione app: mantieni il layer condiviso modulare così mandi in produzione solo ciò che l'app necessita.
- Batteria/dati: raggruppa le chiamate di rete ed evita polling aggressivo.
- Permessi: richiedi solo quando necessario (fotocamera, posizione, contatti) e tieni i controlli dei permessi fuori dal codice di dominio così le policy possono variare per piattaforma.
Modelli di dati, auth e permessi su tutte le superfici
Un “single codebase” si rompe rapidamente se web, mobile e API inventano forme di dati e regole di sicurezza diverse. La soluzione è trattare modelli, autenticazione e autorizzazione come decisioni di prodotto condivise, poi codificarle una volta sola.
Una fonte di verità per i modelli di dati
Scegli un posto unico dove vivono i modelli, e fai derivare tutto il resto da lì. Opzioni comuni:
- Schema-first: definisci entità e regole di validazione in file di schema (es. OpenAPI/JSON Schema), poi genera tipi per API, web e mobile.
- Moduli condivisi: conserva tipi e validator in un pacchetto condiviso (spesso il package “domain”) che tutte le app importano.
- Ibrido: file di schema per i contratti esterni, moduli condivisi per le regole di dominio interne.
La chiave non è lo strumento—è la coerenza. Se “OrderStatus” ha cinque valori in un client e sei in un altro, il codice generato dall'AI compilerà comunque e introdurrà bug.
Autenticazione: sessioni, token e storage sicuro
L'autenticazione deve essere percepita dall'utente come unica, ma la meccanica varia per superficie:
- Web spesso preferisce sessioni basate su cookie (buone per CSRF, semplice per il browser).
- Mobile e client terzi solitamente richiedono auth token (access token + refresh token).
Progetta un flusso unico: login → accesso a breve durata → refresh quando necessario → logout che invalida lo stato server-side. Sul mobile conserva segreti in secure storage (Keychain/Keystore), non in preferenze plain. Sul web preferisci cookie httpOnly così i token non sono esposti a JavaScript.
Autorizzazione: regole centrali applicate dall'API
I permessi dovrebbero essere definiti una volta—idealmente vicino alle regole di business—poi applicati ovunque.
- Centralizza i controlli nel domain layer (es.
canApproveInvoice(user, invoice)). - Falli rispettare nell'API per sicurezza reale.
- Replicali nella UI solo per nascondere/disabilitare azioni, non per proteggere i dati.
Questo evita la deriva “funziona su mobile ma non su web” e dà alla generazione AI un contratto chiaro e testabile su chi può fare cosa.
Strategia di build, release e deployment
Un codebase unificato resta tale solo se build e release sono prevedibili. L'obiettivo è permettere ai team di distribuire API, web app e mobile app in modo indipendente—senza forkare la logica o aggiungere "special case" per gli ambienti.
Monorepo vs multi-repo
Un monorepo (un repo, più pacchetti/app) tende a funzionare meglio per un single codebase perché logica di dominio, contratti API e client UI evolvono insieme. Ottieni cambi atomici (una PR aggiorna un contratto e tutti i consumer) e refactor più semplici.
Un multi-repo può comunque restare unificato, ma pagherai in coordinazione: versioning dei pacchetti condivisi, pubblicazione di artefatti e sincronizzazione dei breaking change. Scegli multi-repo solo se confini organizzativi, regole di sicurezza o scala lo rendono impraticabile.
Target di build e artefatti
Tratta ogni superficie come un target di build separato che consuma pacchetti condivisi:
- Artefatto servizio API: immagine container o bundle serverless costruito dal package API.
- Bundle web: asset statici + runtime server (se SSR) costruito dal package web.
- Build mobile: Android (AAB/APK) e iOS (IPA) prodotti da pipeline native che integrano la logica condivisa come dipendenza.
Mantieni gli output di build espliciti e riproducibili (lockfile, toolchain pinned, build deterministiche).
Pipeline CI/CD e separazione degli ambienti
Una pipeline tipica è: lint → typecheck → unit tests → contract tests → build → security scan → deploy.
Separa config da codice: variabili d'ambiente e segreti vivono nel tuo CI/CD e secret manager, non nel repo. Usa overlay per ambienti (dev/stage/prod) così lo stesso artefatto può essere promosso tra ambienti senza ricompilarlo—soprattutto per API e runtime web.
Test e gate di qualità per il codice condiviso
Quando web, mobile e API vengono rilasciati dallo stesso codebase, i test smettono di essere “un altro checkbox” e diventano il meccanismo che impedisce a una piccola modifica di rompere tre prodotti contemporaneamente. L'obiettivo è semplice: individuare i problemi dove costa meno correggerli e bloccare i cambi rischiosi prima che raggiungano gli utenti.
Piramide dei test pratica per un codebase condiviso
Inizia dal dominio condiviso (la logica di business) perché è la più riutilizzata e il posto più facile per testare senza infrastrutture lente.
- Unit test (domain layer): verifica regole come pricing, idoneità, decisioni di permesso, transizioni di stato e casi limite. Devono essere veloci e rappresentare la maggior parte della suite.
- Integration test (API layer): dimostrano che l'API funziona end-to-end con serializzazione reale, validazione, autenticazione e accesso ai dati. Mantienili focalizzati sui flussi critici piuttosto che su ogni angolo.
- UI test (per client): un piccolo numero di controlli ad alto valore per web e mobile che confermano i percorsi chiave (sign-in, checkout, invio form). Sono più lenti, quindi usali come “allarmi” più che come prova esaustiva.
Questa struttura concentra la maggior parte della fiducia nella logica condivisa, pur catturando problemi di wiring dove i layer si incontrano.
Contract testing per mantenere allineati client e API
Anche in un monorepo è facile che l'API cambi in modo compatibile a compile-time ma che rompa l'esperienza utente. I test di contratto prevengono la deriva silenziosa.
- Contratti API→client: blocca forme request/response, formati di errore e status codes. Se l'API ritorna un nuovo campo richiesto o cambia un valore enum, i contract test falliscono prima della merge.
- Schema come gate: se pubblichi schemi OpenAPI/GraphQL, tratta le modifiche di schema come artefatti revisionabili. I breaking change dovrebbero richiedere approvazione esplicita e un piano di migrazione.
Gate di qualità che proteggono i rilasci
I buoni test contano, ma contano anche le regole attorno ad essi.
- Gate su PR: richiedi unit + integration tests passati, lint/format e copertura minima sul domain layer.
- Feature flag: distribuisci codice in sicurezza nascondendo comportamenti incompleti dietro flag abilitabili per ambiente o gruppi utente.
- Rollout graduale: rilascia prima agli utenti interni, poi a una piccola percentuale di traffico, poi a tutti.
- Piano di rollback: rendi il rollback un risultato di prima classe—release versionate, migrazioni DB reversibili (o procedura di safe forward) e criteri chiari per "fermare la linea".
Con questi gate, i cambi generati dall'AI possono essere frequenti senza diventare fragili.
Come usare l'AI senza perdere il controllo dell'architettura
L'AI può accelerare un codebase unico, ma solo se trattata come un rapido ingegnere junior: brava a produrre bozze, non affidabile da fondere senza revisione. L'obiettivo è usare l'AI per velocità mantenendo la responsabilità umana sull'architettura, i contratti e la coerenza a lungo termine.
Dove l'AI aiuta di più (e a basso rischio)
Usa l'AI per generare le “prime versioni” che altrimenti scriveresti meccanicamente:
- Scaffold di progetto (cartelle, moduli boilerplate, feature skeleton)
- Documentazione API ed esempi basati su contratti esistenti
- Suite di test (unit attorno alle regole di dominio, contract test per gli endpoint)
- Migrazioni e script di seed
- Refactor ripetitivi (rinomina campi, separa moduli), dopo aver definito il piano
Una buona regola: lascia che l'AI produca codice facile da verificare leggendo o eseguendo i test, non codice che cambi silenziosamente il significato di business.
Guardrail che proteggono l'architettura
L'output AI dovrebbe essere vincolato da regole esplicite, non da impressioni. Metti queste regole dove vive il codice:
- Standard di codice: linters/formatters, regole di naming e "no direct DB access from UI" come vincoli stilistici.
- Regole architetturali: confini di dipendenza (es. domain layer non può importare API/web/mobile), applicate tramite tooling o semplici controlli di build.
- Checklist PR: “Contratto cambiato? Aggiorna OpenAPI + tipi client + test.” “Nuova regola di dominio? Aggiungi test di dominio.”
Se l'AI suggerisce una scorciatoia che viola i confini, la risposta è “no”, anche se compila.
Governance: rendi l'AI auditable
Il rischio non è solo codice scadente—sono decisioni non tracciate. Mantieni una traccia di audit:
- Salva prompt e risposte chiave insieme agli item di lavoro (ID ticket, link PR).
- Registra decisioni architetturali (ADR) per cambi di contratto, modelli auth o nuovi concetti di dominio.
- Richiedi che i cambi API siano espliciti: versionati, documentati e supportati da contract test.
L'AI è più preziosa quando è ripetibile: il team può vedere perché qualcosa è stata generata, verificarla e rigenerarla in sicurezza quando i requisiti evolvono.
Nota sugli strumenti: AI che rispetta i confini
Se stai adottando lo sviluppo assistito dall'AI a livello di sistema (web + API + mobile), la caratteristica più importante non è la pura velocità di generazione—è la capacità di mantenere l'output allineato con i tuoi contratti e layering.
Per esempio, Koder.ai è una piattaforma vibe-coding che aiuta i team a costruire applicazioni web, server e mobile tramite un'interfaccia chat—pur producendo codice sorgente reale ed esportabile. In pratica, questo è utile per il workflow descritto in questo articolo: puoi definire un contratto API e regole di dominio, poi iterare rapidamente su superfici web React, backend Go + PostgreSQL e app Flutter senza perdere la possibilità di revisionare, testare e far rispettare i confini architetturali. Funzionalità come planning mode, snapshot e rollback si integrano bene con la disciplina "genera → verifica → promuovi" in un codebase unificato.
Domande frequenti
"Un codebase AI-generated" significa un'unica UI che gira ovunque?
Di solito significa un repository e un insieme condiviso di regole, non un'app identica per tutte le piattaforme.
In pratica, web, mobile e API condividono uno strato di dominio (regole di business, validazione, casi d'uso) e spesso un unico contratto API, mentre ogni piattaforma mantiene la propria UI e le integrazioni specifiche.
Cosa dovrebbe essere condiviso tra web, mobile e API — e cosa no?
Condividi ciò che non può mai essere in conflitto:
- Regole di dominio (pricing, idoneità, workflow, invarianti)
- Casi d'uso (create order, cancel subscription, issue refund)
- Validazione + codici di errore
- Schemi/contratti API (OpenAPI/GraphQL) e tipi generati
Mantieni i componenti UI, la navigazione e le integrazioni dispositivo/browser specifici per piattaforma.
Cosa cambia l'AI nell'architettura, e cosa resta uguale?
L'AI accelera la scaffolding e i lavori ripetitivi (CRUD, clienti, test), ma non crea automaticamente buoni confini.
Senza un'architettura intenzionale, il codice generato dall'AI spesso:
- duplica la logica tra le app
- mescola responsabilità (la UI che accede direttamente ai dati)
- crea convalide leggermente diverse in più posti
Usa l'AI per riempire parti ben definite, non per inventare gli strati.
Qual è una buona architettura di riferimento per un unico codebase condiviso?
Un flusso semplice e affidabile è:
- Client (web/mobile/partners) → API layer
- L'API traduce le richieste in use case di dominio
- Il dominio chiama le interfacce delle fonti dati (DB/cache/API esterne)
Questo mantiene le regole di business centralizzate e rende più semplice testare e revisionare le aggiunte generate dall'AI.
Come preveniamo la deriva della validazione tra web, mobile e API?
Metti la validazione in un unico posto (nel dominio o in un modulo di validazione condiviso), poi riusala ovunque.
Pattern pratici:
- valida oggetti di valore come
EmailAddresseMoneyuna sola volta - applica regole cross-field nei casi d'uso (es. intervalli di date)
- restituisci codici di errore stabili (la UI mappa i codici sui messaggi)
Così eviti che «il web lo accetta, l'API lo rifiuta».
Come può il contratto API diventare la "fonte di verità" per tutto il sistema?
Usa uno schema canonico come OpenAPI (o GraphQL SDL) e genera a partire da quello:
- stub server e scaffolding di validazione
- client tipizzati per web e mobile
- modelli request/response condivisi
Poi aggiungi test di contratto così le modifiche che rompono lo schema falliscono in CI prima di essere rilasciate.
Cosa significa "offline-first" quando si condivide la logica con un'app mobile?
Progetta l'offline intenzionalmente invece di «sperare che la cache funzioni»:
- memorizza localmente modelli di lettura con una politica di staleness chiara
- metti in coda le scritture come intenti/eventi e sincronizza quando sei online
- definisci regole di conflitto (server-authoritative, merge, o risoluzione utente)
- usa retry con backoff e idempotency keys
Mantieni storage e sync nel layer mobile; le regole di business restano nel dominio condiviso.
Come dovrebbero funzionare auth e permessi su web, mobile e API?
Usa un unico flusso concettuale, implementato diversamente per superficie:
- Web: spesso sessioni via cookie httpOnly (riduce l'esposizione dei token a JS)
- Mobile/terze parti: access + refresh token, conservati in secure storage (Keychain/Keystore)
Le regole di autorizzazione vanno definite centralmente (es. canApproveInvoice) e fatte rispettare nell'API; la UI le replica solo per nascondere/disabilitare azioni.
Come mantenere gestibili build e release in un codebase unificato?
Tratta ogni superficie come un target di build separato che consuma pacchetti condivisi:
- API: immagine container o bundle serverless
- Web: bundle statico + runtime SSR se necessario
- Mobile: build native iOS/Android che importano la logica condivisa
In CI/CD esegui: lint → typecheck → unit tests → contract tests → build → security scan → deploy, e tieni segreti/config fuori dal repo.
Come usiamo l'AI per accelerare lo sviluppo senza perdere il controllo architetturale?
Usa l'AI come un ingegnere junior veloce: ottima per bozze, non sicura da unire senza guardrail.
Buoni guardrail:
- far rispettare i confini di dipendenza (il dominio non può importare web/mobile/API)
- richiedere aggiornamenti di schema + client quando il contratto cambia
- imporre unit test di dominio per nuove regole
- collegare ADR e prompt chiave a PR/ticket
Se l'output AI viola le regole architetturali, respingilo anche se compila.