Nexum - Onboarding Dev

Bigino tecnico per entrare nel progetto. Tieni questa pagina a portata di mano.

Indice: Overview Stack Architettura Integrations Ambienti Team Comunicazione Setup Dev Deploy Issue Aperti Incident Gotchas

Cos'e Nexum

Piattaforma web per la vendita di polizze e garanzie estese (warranty sui prodotti). I clienti finali di Estendo (Dimo, Maico, Smartsound, ENEL in arrivo) la usano ogni giorno per vendere garanzie ai loro clienti.

Volume reale: ~29 contratti/giorno solo su Dimo. Non e un side project.

giobi.com (dev) Netycom (contratto) Estendo (cliente) Dimo / Maico / Smartsound / ENEL

Tu entreresti nella prima casella, fianco a fianco con Giobi.

Stack Tecnico

CosaTecnologiaNote
Backend Laravel PHP 8.2+ Framework principale. Se non lo conosci, e il prerequisito #1
Frontend Livewire + Blade Componenti reattivi server-side, no SPA
Database MySQL Un DB per istanza cliente (isolation)
Pagamenti Zuora Carte di credito + SEPA. Hosted Payment Pages
Archiviazione docs Namirial SolutionDOC Archiviazione elettronica a norma + firma digitale
API Garanzie SOAP + REST API Estendo per marche/prodotti/garanzie
Repo GitHub (privata) github.com/netycom/nexum - org Netycom

Architettura Multi-Tenant

Ogni cliente Estendo ha la propria istanza Nexum: deployment separato, database dedicato, configurazione Zuora specifica, branding personalizzabile.

Cosa e separatoEsempio
Path server/var/www/html/nexum-dimo25/, /nexum-maico/, etc.
Database MySQLUser dedicato per istanza (no root condiviso)
Config ZuoraChiavi API + Page ID per CC e SEPA per ogni cliente
BrandingColori e logo via .env (APP_COLOR_GREEN="#00D72C")
Dominionexumapp.dimo.estendo.it, nexumapp.maico.estendo.it, etc.

Quindi quando lavori su un bug, chiediti sempre: su quale istanza? Staging, demo, Dimo, Maico, Smartsound?

Integrations

Zuora (Pagamenti)

Gotcha critico: Se aggiungi un custom field nel codice Laravel ma NON lo crei in Zuora admin → tutti i pagamenti si bloccano. E' successo in produzione (campo durata__c, Dic 2025).

Namirial SolutionDOC (Archiviazione)

API Estendo (Garanzie)

TipoAmbienteURL
SOAP Test https://supporto.estendo.it:8092/wsgaranzie.asmx
SOAP Produzione https://supporto.estendo.it:8089/wsgaranzie.asmx
REST Nuova https://supporto.estendo.it:8085 (Bearer Token)

REST API docs: SwaggerHub

Ambienti

Staging (Athena)

Cloudways — test prima di prod

estendo.sel.re

Demo/Test Prod

nexumapp.estendo.it

/var/www/html/estendo24/

Dimo (principale)

nexumapp.dimo.estendo.it

/var/www/html/nexum-dimo25/
~29 contratti/giorno

Maico

nexumapp.maico.estendo.it

/var/www/html/nexum-maico/
Basso volume

Smartsound

nexumapp.smartsound.estendo.it

/var/www/html/nexum-smartsound/
Volume medio

ENEL (in setup)

nexumapp.enel.estendo.it

/var/www/html/nexum-enel/
Pending DNS + nginx

Server produzione: 62.173.167.212 (SRVAPPWEB Estendo), user giobi

Regola d'oro: SEMPRE testare su staging (Athena) prima di toccare produzione. MAI deploy diretto su prod.

Team

Ilaria Gobbi
PM operativo — Estendo
Contatto quotidiano. Segnala bug, chiede aggiornamenti. Tecnico ma narrativo.
Paolo Mapelli
Manager — Estendo
Vuole: stato + rischi + decisioni. Non gli servono dettagli tecnici.
Michelangelo Barbieri (Mike)
Sistemista — Estendo
Ultra-tecnico, diretto. Comandi esatti, tono informale. Gestisce il server.
Simone Blardone
CEO — Netycom
Paritetico, problem solving. Nessuna cerimonia. SEMPRE in CC sulle email.
Riccardo Bracci
Dev — Staging Blue
Sviluppatore, usa staging dedicato (nexumblue).
Maurizio
Support — Namirial
Referente per archiviazione documenti. Ticket quando serve.

Comunicazione

Email

Regola CC: Paolo Mapelli (paolo.mapelli@estendo.it) e Simone Blardone (simone.blardone@netycom.it) vanno SEMPRE in CC nelle email verso Estendo.

Tono

Setup Dev Environment

Requisiti

Primo setup

git clone git@github.com:netycom/nexum.git
cd nexum
composer install
npm install
cp .env.example .env
# Configura: DB locale, chiavi Zuora staging, config Namirial test, API Estendo test
php artisan key:generate
php artisan migrate
npm run dev

Repo

GitHub privata: github.com/netycom/nexum (org Netycom). Serve accesso — chiedere a Giobi o Blardone.

Issue Aperti (snapshot Feb 2026)

19 issue aperti su GitHub, divisi per categoria:

Bug (3)

#Titolo
#95KO pulsante "Mostra i contratti della sede corrente" - In sospeso
#92Inserimento colonna Punto Vendita scarico CSV Venduto e Recessi
#36Recessi - pulsante vedi tutte le sedi non funziona

Enhancement (5)

#Titolo
#94Verifica latenza pagamento piattaforma di vendita
#89Pulizia recessi piattaforma DIMO
#86Prodotti e telefonia - implementare API REST con JSON
#31Dati fatturazione piattaforma
#30Zuora - Campi aggiuntivi

Backlog (5)

#Titolo
#65Delegare logica pagamento a ContractPaymentHandler
#64Aggiungere exception catch per API Estendo
#55Refactoring getDocuments per il contract
#54Allestimento branch staging
#28Logging attivita clienti finali sul portale
Per iniziare: Issue dal backlog come #86 (API REST prodotti) o #92 (CSV export) sono buoni task isolati per prendere confidenza con il codebase senza rischiare di rompere nulla in produzione.

Gotchas & Lezioni dal Campo

Zuora custom fields: Se aggiungi un campo __c nel codice ma non lo crei in Zuora admin → pagamenti bloccati per TUTTI. Successo con durata__c (Dic 2025, contratti #239 e #244 impattati).
Blade section pollution: @section("content") nei template email inquina il @yield("content") del layout pagina se Mail::send() e sincrono nel mount() Livewire. Fix: view()->flushSections() dopo il send.
Config .env colori hex: I valori #hex vanno tra virgolette: APP_COLOR_GREEN="#00D72C". Senza virgolette # = commento → valore vuoto → tutto bianco.
Cron scheduler: Serve chmod -R 777 storage/framework/cache ogni ora via crontab, altrimenti il scheduler crasha. Non dimenticare anche storage/logs.
Bug strpos storico: strpos('smartsound.', $url) invece di strpos($url, 'smartsound.') → tutti gli if falliscono sempre. Config Zuora KO su tutti i clienti.
Permessi storage: Owner deve essere www-data, non giobi:root. Se artisan e bloccato → svuotare bootstrap/cache via script PHP web.

Deploy: Envoyer & Zero-Downtime

Nexum usa Envoyer (SaaS di Laravel, 12$/mese) per il deploy. Il concetto chiave e il zero-downtime deployment via symlink: gli utenti non vedono MAI un "sito in manutenzione".

Come funziona

Envoyer non sovrascrive i file. Ogni deploy crea una nuova cartella release, ci installa tutto, e solo alla fine sposta il symlink current. Se qualcosa va storto, il symlink torna alla release precedente.

/var/www/html/nexum-dimo25/
│
├── current → releases/20260219093000/    ← symlink (nginx punta qui)
│
├── releases/
│   ├── 20260219093000/    ← release attiva (ultima)
│   │   ├── app/
│   │   ├── bootstrap/
│   │   ├── config/
│   │   ├── public/
│   │   ├── resources/
│   │   ├── routes/
│   │   ├── vendor/         ← composer install (fresh ogni release)
│   │   ├── .env → ../../.env   ← symlink al .env condiviso
│   │   └── storage → ../../storage/   ← symlink allo storage condiviso
│   │
│   ├── 20260218140000/    ← release precedente (rollback pronto)
│   ├── 20260215120000/    ← vecchia (Envoyer tiene le ultime N)
│   └── ...
│
├── .env                    ← ENV condiviso tra tutte le release
│                             (DB creds, Zuora keys, colori, etc.)
│
└── storage/                ← storage condiviso (persistente)
    ├── app/
    ├── framework/
    │   ├── cache/
    │   ├── sessions/
    │   └── views/
    └── logs/

Sequenza di un deploy

flowchart TD
    A["🔀 git push main"] --> B["1. CLONE\nClona repo in releases/YYYYMMDDHHMMSS/"]
    B --> C["2. INSTALL\ncomposer install --no-dev\nnpm install && npm run build"]
    C --> D["3. SYMLINK\n.env → ../../.env\nstorage → ../../storage"]
    D --> E["4. HOOKS\nphp artisan migrate --force\nphp artisan config:cache\nphp artisan route:cache"]
    E --> F["5. SWITCH ⚡\ncurrent → releases/NUOVO/\n(atomico: un singolo mv)"]
    F --> G["6. CLEANUP\nRimuove release vecchie\n(tiene ultime 5)"]

    style A fill:#444,stroke:#666,color:#fff
    style F fill:#ff6600,stroke:#cc5200,color:#fff
    style G fill:#2a6e2a,stroke:#1a4e1a,color:#fff
        
Perche e zero-downtime: nginx punta a current/. Finche il symlink non cambia, gli utenti vedono la release vecchia. Il cambio symlink e atomico (una singola operazione del filesystem). Nessun momento in cui il sito e "mezzo aggiornato".

Cose da sapere

CosaDettaglio
.envCondiviso, sta FUORI dalle release. Modifichi una volta, vale per tutti i deploy
storage/Condiviso e persistente. Upload, cache, log, sessioni sopravvivono ai deploy
vendor/Reinstallato fresh ad ogni release (no symlink, dentro la release)
RollbackBasta spostare il symlink current alla release precedente. Istantaneo
BranchConfigurato per istanza. Default: main. Se pusho su staging, Envoyer non deploya
Gotcha permessi: storage/ e bootstrap/cache/ devono essere scrivibili da www-data. Dopo un deploy, se i permessi sono sbagliati, il sito crasha. Per questo c'e un cron chmod -R 777 ogni ora come safety net.
Transizione in corso: Estendo (Mike/Mapelli) sta valutando il passaggio da Envoyer a Jenkins per avere piu controllo. La struttura directory potrebbe cambiare — chiedi prima di assumere.

Top 5 Incident — Casistiche Reali

Roba che e successa davvero in produzione. Leggile, memorizzale, evita di ripeterle.

CRITICAL 4 Dic 2025

Triple-fault: permessi + timeout SOAP + config Zuora

Tre problemi interconnessi, scoperti tutti insieme. Piattaforme in ginocchio.

ProblemaCausa rootResponsabilita
Permessi storageOwner giobi:root invece di www-dataInfrastruttura (Estendo)
Timeout SOAP 2minFont PDF 404 → blocco generazione → timeout a catenaEstendo (risorsa mancante)
Config Zuora KOBug strpos invertito in zuora.phpNostro codice

Il bug: strpos('smartsound.', $url) invece di strpos($url, 'smartsound.') — parametri invertiti, tutti gli if falliscono sempre. Nessun cliente riceveva la config Zuora corretta.

Postmortem
  • Detection: Segnalazione Ilaria — piattaforme non funzionanti
  • Triage: Accesso da cellulare (durante ferie), analisi remota
  • Root cause: 3 cause indipendenti sovrapposte. Il bug strpos era latente da mesi, mascherato dal workaround .env
  • Resolution: Workaround immediato (valori Zuora in .env). Fix strpos deployato dopo
  • Tempo down: ~4h (risolto da remoto)
  • Action items: Separare sempre causa nostra / infrastruttura / terze parti. Tabella responsabilita in ogni incident report
CRITICAL 12 Dic 2025

Zuora rifiuta tutti i pagamenti: custom field fantasma

Pagamenti bloccati su Dimo dalle 13:00. Zuora rifiuta ogni subscription con:

Invalid custom fields: 'durata__c' (code 58630120)

Causa: Il campo durata__c era stato aggiunto al codice PHP ma non creato in Zuora come custom field sulla Subscription. Zuora non accetta campi che non conosce.

Contratti impattati: #239, #244 (e potenzialmente altri).

Postmortem
  • Detection: Errori nei log Zuora a partire dalle ~13:00, segnalazione Ilaria
  • Root cause: Disallineamento codice/config — il campo era nel codice Laravel ma non esisteva in Zuora. Nessuna validazione preventiva
  • Resolution: Rimosso durata__c dal payload come workaround. Campo creato in Zuora admin successivamente
  • Tempo down: ~3h (pagamenti bloccati per tutti i clienti Dimo)
  • Action items: Checklist pre-deploy: ogni custom field __c va verificato in Zuora admin PRIMA del merge. Mai assumere che "qualcun altro lo ha configurato"
HIGH 25 Nov 2025

Hotfix day Dimo: 4 bug critici in un giorno

Giornata di fuoco su Dimo appena andato live (v15). Quattro bug bloccanti scoperti in rapida successione:

IssueProblemaFix
#84Pagamento CC KOPage ID Zuora sbagliati (CC + SEPA)
#85Modelli telefono non disponibiliImport manuale DB, fix definitivo in #86
#87Contatore n. polizza mancanteFix staging → produzione
#88Recesso contratto impossibileErrore su "tutte le sedi"
Postmortem
  • Detection: Go-live Dimo v15, bug scoperti dagli operatori nei primi minuti di utilizzo
  • Root cause: Config Zuora copiata dal template senza aggiornare i Page ID specifici per Dimo. DB prodotti incompleto (mancavano modelli telefono)
  • Resolution: Fix seriale in giornata, 4 issue chiusi. Page ID Dimo: CC 8a28927c..., SEPA 8a28a3a9...
  • Tempo down: ~6h (vari fix durante la giornata, operativi bloccati a intermittenza)
  • Action items: Checklist nuova istanza creata (ora documentata). Ogni istanza ha i propri Page ID — non copiare, verificare
MEDIUM 11 Feb 2026

Blade section pollution: email che rompe la pagina

Il template email usava @section("content") che inquinava il @yield("content") del layout pagina, perche Mail::send() veniva chiamato sincronamente dentro il mount() di Livewire.

Sintomo: Dopo l'invio email, la pagina mostrava il contenuto dell'email al posto del contenuto normale.

Fix: view()->flushSections() dopo ogni Mail::send().

Postmortem
  • Detection: Testing su staging (Athena) — pagina mostra contenuto email invece del contenuto normale
  • Root cause: Laravel/Blade mantiene le sections in memoria. Mail::send() sincrono nel mount() Livewire compila il template email, che registra una @section("content") che sovrascrive quella della pagina
  • Resolution: Una riga: view()->flushSections() dopo il send. Fix applicato in NamirialSignStep.php
  • Tempo down: 0 (catturato su staging prima di prod)
  • Action items: Usare queue per le email. Se sincrono e inevitabile, sempre flush dopo. Attenzione ai side-effect di Blade nei componenti Livewire
MEDIUM 4 Feb 2026

Deploy che non deploya: branch mismatch

Il codice era stato pushato su branch staging, ma Envoyer deployava da main (fermo al 15 gennaio). Risultato: deploy apparentemente ok ma codice vecchio in produzione.

Fix: Merge staging → main + redeploy.

Postmortem
  • Detection: "Ho deployato ma non cambia niente" — codice in prod identico a 3 settimane prima
  • Root cause: Push su staging, Envoyer configurato per deployare da main. Il deploy gira, ma scarica codice vecchio
  • Resolution: Merge staging → main, redeploy
  • Tempo down: ~1h (nessun impatto utenti, solo feature mancanti)
  • Action items: Verificare branch Envoyer quando si configura una nuova istanza. Se il deploy non ha effetto visibile, primo check: branch mismatch

Route di Debug (Admin Only)

RouteCosa fa
/systemDashboard sistema
/system/estendoPlayground REST API Estendo (test marche/prodotti)
/system/paymentPayment Analytics
/system/log/sentryTest Sentry logging
/system/log/stackTest stack logging