Bigino tecnico per entrare nel progetto. Tieni questa pagina a portata di mano.
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.
Tu entreresti nella prima casella, fianco a fianco con Giobi.
| Cosa | Tecnologia | Note |
|---|---|---|
| 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 |
Ogni cliente Estendo ha la propria istanza Nexum: deployment separato, database dedicato, configurazione Zuora specifica, branding personalizzabile.
| Cosa e separato | Esempio |
|---|---|
| Path server | /var/www/html/nexum-dimo25/, /nexum-maico/, etc. |
| Database MySQL | User dedicato per istanza (no root condiviso) |
| Config Zuora | Chiavi API + Page ID per CC e SEPA per ogni cliente |
| Branding | Colori e logo via .env (APP_COLOR_GREEN="#00D72C") |
| Dominio | nexumapp.dimo.estendo.it, nexumapp.maico.estendo.it, etc. |
Quindi quando lavori su un bug, chiediti sempre: su quale istanza? Staging, demo, Dimo, Maico, Smartsound?
tipoProdotto__c, categoriaProdotto__c, modelloProdotto__c, imei__cdurata__c, Dic 2025).
RepositoryService.svc| Tipo | Ambiente | URL |
|---|---|---|
| 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
Cloudways — test prima di prod
estendo.sel.re
nexumapp.estendo.it
/var/www/html/estendo24/
nexumapp.dimo.estendo.it
/var/www/html/nexum-dimo25/nexumapp.maico.estendo.it
/var/www/html/nexum-maico/nexumapp.smartsound.estendo.it
/var/www/html/nexum-smartsound/nexumapp.enel.estendo.it
/var/www/html/nexum-enel/Server produzione: 62.173.167.212 (SRVAPPWEB Estendo), user giobi
#74, #91paolo.mapelli@estendo.it) e Simone Blardone (simone.blardone@netycom.it) vanno SEMPRE in CC nelle email verso Estendo.
netycom su GitHub)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
GitHub privata: github.com/netycom/nexum (org Netycom). Serve accesso — chiedere a Giobi o Blardone.
19 issue aperti su GitHub, divisi per categoria:
| # | Titolo |
|---|---|
| #95 | KO pulsante "Mostra i contratti della sede corrente" - In sospeso |
| #92 | Inserimento colonna Punto Vendita scarico CSV Venduto e Recessi |
| #36 | Recessi - pulsante vedi tutte le sedi non funziona |
| # | Titolo |
|---|---|
| #94 | Verifica latenza pagamento piattaforma di vendita |
| #89 | Pulizia recessi piattaforma DIMO |
| #86 | Prodotti e telefonia - implementare API REST con JSON |
| #31 | Dati fatturazione piattaforma |
| #30 | Zuora - Campi aggiuntivi |
| # | Titolo |
|---|---|
| #65 | Delegare logica pagamento a ContractPaymentHandler |
| #64 | Aggiungere exception catch per API Estendo |
| #55 | Refactoring getDocuments per il contract |
| #54 | Allestimento branch staging |
| #28 | Logging attivita clienti finali sul portale |
__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).
@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.
#hex vanno tra virgolette: APP_COLOR_GREEN="#00D72C". Senza virgolette # = commento → valore vuoto → tutto bianco.
chmod -R 777 storage/framework/cache ogni ora via crontab, altrimenti il scheduler crasha. Non dimenticare anche storage/logs.
strpos('smartsound.', $url) invece di strpos($url, 'smartsound.') → tutti gli if falliscono sempre. Config Zuora KO su tutti i clienti.
www-data, non giobi:root. Se artisan e bloccato → svuotare bootstrap/cache via script PHP web.
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".
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/
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
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".
| Cosa | Dettaglio |
|---|---|
.env | Condiviso, 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) |
| Rollback | Basta spostare il symlink current alla release precedente. Istantaneo |
| Branch | Configurato per istanza. Default: main. Se pusho su staging, Envoyer non deploya |
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.
Roba che e successa davvero in produzione. Leggile, memorizzale, evita di ripeterle.
Tre problemi interconnessi, scoperti tutti insieme. Piattaforme in ginocchio.
| Problema | Causa root | Responsabilita |
|---|---|---|
| Permessi storage | Owner giobi:root invece di www-data | Infrastruttura (Estendo) |
| Timeout SOAP 2min | Font PDF 404 → blocco generazione → timeout a catena | Estendo (risorsa mancante) |
| Config Zuora KO | Bug strpos invertito in zuora.php | Nostro 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.
strpos era latente da mesi, mascherato dal workaround .envPagamenti 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).
durata__c dal payload come workaround. Campo creato in Zuora admin successivamente__c va verificato in Zuora admin PRIMA del merge. Mai assumere che "qualcun altro lo ha configurato"Giornata di fuoco su Dimo appena andato live (v15). Quattro bug bloccanti scoperti in rapida successione:
| Issue | Problema | Fix |
|---|---|---|
| #84 | Pagamento CC KO | Page ID Zuora sbagliati (CC + SEPA) |
| #85 | Modelli telefono non disponibili | Import manuale DB, fix definitivo in #86 |
| #87 | Contatore n. polizza mancante | Fix staging → produzione |
| #88 | Recesso contratto impossibile | Errore su "tutte le sedi" |
8a28927c..., SEPA 8a28a3a9...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().
Mail::send() sincrono nel mount() Livewire compila il template email, che registra una @section("content") che sovrascrive quella della paginaview()->flushSections() dopo il send. Fix applicato in NamirialSignStep.phpIl 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.
staging, Envoyer configurato per deployare da main. Il deploy gira, ma scarica codice vecchiostaging → main, redeploy| Route | Cosa fa |
|---|---|
/system | Dashboard sistema |
/system/estendo | Playground REST API Estendo (test marche/prodotti) |
/system/payment | Payment Analytics |
/system/log/sentry | Test Sentry logging |
/system/log/stack | Test stack logging |