Progetto: Portale Immobiliare Immobiliaris
Team: Connectwork (Gruppo 5) - ITS Academy ICT Piemonte
Stack: Spring Boot 3.5.7 (Java 21) + React 19 + H2 Database + Vite
| Ruoli | Nomi | Responsabilità |
|---|---|---|
| Software Developers | BENAGOUB OMAR @Omarben05 VARDÉ DOMENICO @domenicovarde PIZZORNO SIMONE @Simone-Pix |
Backend, API REST, Database H2, Logiche valutazione automatica, Integrazione Brevo |
| Web Developers | CENNI VITTORIO @ViTz1 GIRAUDO ANDREA @AndreaXVII17 CACHI YOSSIANI MAYTÉ @MayteCachi |
Frontend React, UX/UI, Componenti riutilizzabili, Integrazione API, Ottimizzazione SEO on-page |
| Digital Strategists | MUSSANO ILARIA @ilariamussano-cyber CHIUSOLO SAVERIO @saveriochiusolo-cell ALLIETTA TOMMASO @tommasoallietta-beep |
Branding, Logo, Visual Identity, SEO Strategy, Campagne Meta/Google Ads, Lead Generation |
Progetto sviluppato per: ITS Academy ICT Piemonte – Laboratorio Integrato Biennio 2024/2026
- Prerequisiti
- Clonare il Repository
- Struttura del Progetto
- Configurazione Backend
- Architettura Backend & Pattern DTO
- Configurazione Frontend
- Architettura Frontend React
- Avvio del Progetto
- Database H2
- Verifica Funzionamento
- Configurazione Email Brevo
- Guida Completa Integrazione Brevo
- Troubleshooting
| Software | Versione Minima | Download |
|---|---|---|
| Java Development Kit (JDK) | 21 | Oracle JDK 21 o OpenJDK 21 |
| Maven | 3.9+ | Apache Maven (o wrapper incluso) |
| Node.js | 20+ | Node.js |
| Git | 2.40+ | Git SCM |
| IDE (opzionale) | - | VS Code, IntelliJ IDEA, o Eclipse |
Apri un terminale (PowerShell su Windows, Terminal su macOS/Linux) e verifica:
# Verifica Java (deve essere versione 21.x.x)
java -version
# Verifica Maven
mvn -version
# Verifica Node.js
node -v
# Verifica npm
npm -v
# Verifica Git
git --versionOutput atteso:
java version "21.0.x"
Apache Maven 3.9.x
v20.x.x (Node.js)
10.x.x (npm)
git version 2.x.x
# Naviga nella cartella dove vuoi salvare il progetto
cd C:\Users\TuoNome\Desktop
# Clona il repository
git clone https://github.com/Simone-Pix/Connectwork.git
# Entra nella cartella del progetto
cd Connectworkgit clone git@github.com:Simone-Pix/Connectwork.git
cd ConnectworkIl progetto ha due branch principali:
# Visualizza tutti i branch
git branch -a
# Cambia branch se necessario
git checkout main # Branch principale stabile
git checkout SaimonCose # Branch di sviluppoConnectwork/
│
├── backend/ # Backend Spring Boot
│ ├── src/
│ │ ├── main/
│ │ │ ├── java/
│ │ │ │ └── com/immobiliaris/backend/
│ │ │ │ ├── config/ # Configurazioni (CORS, Security)
│ │ │ │ ├── controller/ # REST Controllers
│ │ │ │ ├── dto/ # Data Transfer Objects
│ │ │ │ ├── model/ # Entità JPA
│ │ │ │ ├── repo/ # Repository JPA
│ │ │ │ ├── service/ # Business Logic
│ │ │ │ └── util/ # Utility classes
│ │ │ └── resources/
│ │ │ ├── application.properties # Configurazione Spring Boot
│ │ │ ├── schema.sql # Schema database H2
│ │ │ ├── data.sql # Dati iniziali (utenti, zone_prezzi)
│ │ │ └── static/immagini/ # Immagini statiche
│ │ └── test/ # Test unitari
│ ├── data/ # Database H2 persistente (creato al primo avvio)
│ ├── pom.xml # Dipendenze Maven
│ ├── mvnw / mvnw.cmd # Maven Wrapper (no installazione Maven richiesta)
│ └── README_BREVO.md # Documentazione integrazione email
│
├── frontend/ # Frontend React + Vite
│ ├── src/
│ │ ├── assets/ # Immagini, loghi
│ │ ├── components/ # Componenti React riutilizzabili
│ │ ├── Contexts/ # Context API (AuthContext)
│ │ ├── Layout/ # Layout principale
│ │ ├── pages/ # Pagine (Home, Backoffice, PersonalArea, ecc.)
│ │ ├── styles/ # CSS/Tailwind custom
│ │ ├── App.jsx # Componente root
│ │ └── main.jsx # Entry point
│ ├── public/ # File pubblici
│ ├── package.json # Dipendenze npm
│ ├── vite.config.js # Configurazione Vite
│ └── tailwind.config.js # Configurazione Tailwind CSS
│
├── immagine_caricate/ # Upload utente (non tracciato da Git)
├── README.md # Documentazione generale progetto
├── READMEBACKEND.md # Documentazione pattern DTO
└── .gitignore # File esclusi da Git
cd backendOpzione A: Con Maven installato
mvn clean installOpzione B: Con Maven Wrapper (consigliato, no installazione Maven richiesta)
# Windows PowerShell
.\mvnw.cmd clean install
# macOS/Linux
./mvnw clean installQuesto comando:
- Scarica tutte le dipendenze da
pom.xml - Compila il codice Java
- Esegue i test
- Crea il file JAR in
target/backend-0.0.1-SNAPSHOT.jar
Il database H2 è embedded e persistente (salva i dati su file).
File: src/main/resources/application.properties
# Database H2 file-based (persistente)
spring.datasource.url=jdbc:h2:file:./data/immobiliaris
spring.datasource.username=sa
spring.datasource.password=
# Hibernate: aggiorna schema senza perdere dati
spring.jpa.hibernate.ddl-auto=update
# Console H2 accessibile su http://localhost:8080/h2
spring.h2.console.enabled=true
spring.h2.console.path=/h2
# Non esegue data.sql a ogni avvio (preserva dati)
spring.sql.init.mode=never- Al primo avvio viene creata la cartella
backend/data/con il fileimmobiliaris.mv.db - NON eliminare questa cartella se vuoi preservare i dati
- Per resettare il database: elimina
backend/data/e riavvia il backend
backend/data/immobiliaris.mv.db(database principale)backend/data/immobiliaris.trace.db(log transazioni)
Questi file vengono creati automaticamente al primo avvio e contengono già:
- 48 zone prezzi Piemonte (Torino: 36 CAP, altre città: 12)
- Schema completo delle 9 tabelle (users, immobili, richieste, valutazioni, ecc.)
File data.sql: Contiene SOLO dati di esempio opzionali:
- 3 utenti di test (admin:
andrea.verdi@email.com/ password:1234) - 4 immobili di esempio
- Valutazioni, contratti, immagini di esempio
Configurazione attuale (application.properties):
spring.sql.init.mode=never # NON esegue data.sql (preserva dati esistenti)Per caricare dati di esempio (solo se database vuoto):
- Modifica
application.properties:spring.sql.init.mode=always - Avvia il backend (vedi Sezione 6)
- Dopo il primo avvio, torna a
never:(altrimenti i dati vengono sovrascritti a ogni riavvio)spring.sql.init.mode=never
Per resettare completamente il database:
# Elimina i file persistenti
Remove-Item backend/data/immobiliaris.mv.db
Remove-Item backend/data/immobiliaris.trace.db
# Riavvia backend → verranno ricreati automaticamenteFile: src/main/java/com/immobiliaris/backend/config/CorsConfig.java
.allowedOrigins("http://localhost:5173") // Vite default portSe il frontend gira su porta diversa, modifica questa linea.
Dato che il frontend gira sulla porta: localhost:5173 nel caso venisse aperta una porta differente, assicurarsi di avere la porta del progetto libera e riavviare il progetto per avere tutte le funzionalità disponibili.
Il backend segue un'architettura MVC (Model-View-Controller) con Spring Boot:
Controller (REST API)
↓
Service (Business Logic)
↓
Repository (JPA)
↓
Database (H2)
Layer principali:
- Controller: Gestisce richieste HTTP, validazione input, ritorna DTO
- Service: Logica di business, orchestrazione operazioni complesse
- Repository: Accesso dati tramite Spring Data JPA
- Entity: Rappresentazione tabelle database (JPA)
- DTO: Data Transfer Objects per input/output API
Il progetto utilizza DTO distinti per input e output invece di esporre direttamente le entità JPA. Esempio: ImmobileCreateDTO (input) vs ImmobiliDTO (output).
Vantaggi:
-
Sicurezza: Prevenzione di field spoofing
- Client non può impostare
id,dataCreazione, valori calcolati - Evita mass assignment vulnerabilities
- Client non può impostare
-
Manutenibilità: Separazione responsabilità
- Input: campi richiesti per creazione (es.
superficie,numeroLocali) - Output: include campi generati (
id,timestamp, relazioni calcolate)
- Input: campi richiesti per creazione (es.
-
Validazione: Regole diverse per input/output
- Input: validazioni
@NotNull,@Size,@Pattern - Output: può includere campi nullable o derivati
- Input: validazioni
-
Evoluzione: Aggiungi campi output senza breaking changes
- Nuovi campi calcolati non rompono contratti di creazione
- Client ricevono più dati mantenendo compatibilità
Creazione immobile (POST):
// ImmobileCreateDTO.java (INPUT)
public class ImmobileCreateDTO {
@NotNull
private String indirizzo;
@NotNull
@Positive
private BigDecimal superficie;
@NotNull
private Integer numeroLocali;
// NO id, NO dataCreazione, NO dataUltimoAggiornamento
}Risposta immobile (GET):
// ImmobiliDTO.java (OUTPUT)
public class ImmobiliDTO {
private Long id; // Generato dal DB
private String indirizzo;
private BigDecimal superficie;
private Integer numeroLocali;
private LocalDate dataCreazione; // Timestamp automatico
private LocalDate dataUltimoAggiornamento;
private String nomeProprietario; // Join calcolato
private BigDecimal valutazioneStimata; // Campo calcolato
}- MapStruct per conversioni: Mapping automatico Entity ↔ DTO
- Validazione con Bean Validation: Annotazioni
@Valid,@NotNull,@Size - Documentazione Swagger: Schemi separati per request/response
- Naming convention:
*CreateDTO(input),*DTO(output),*UpdateDTO(patch)
| Endpoint | DTO Input | DTO Output | Rationale |
|---|---|---|---|
POST /api/immobili |
ImmobileCreateDTO |
ImmobiliDTO |
Client fornisce dati obbligatori, server genera id/timestamp |
GET /api/immobili/{id} |
- | ImmobiliDTO |
Include relazioni calcolate (proprietario, valutazione) |
POST /api/richieste/valuta |
RichiesteCreateDTO |
ValutazioneDTO |
Input: dati immobile, Output: valutazione calcolata |
POST /api/richieste/converti |
Long (richiesta_id) |
ImmobiliDTO |
Converte richiesta in immobile permanente |
Scenario: Utente richiede valutazione immobile
1. POST /api/richieste/valuta
Input: RichiesteCreateDTO (superficie, locali, zona...)
↓
2. RichiesteController.valuaRichiestaAutomatica()
- Crea entità Richieste
- Calcola valutazione con ZonePrezziRepository
- Salva Valutazioni con richiesta_id
↓
3. Output: ValutazioneDTO (prezzoMinimo, prezzoMassimo, coefficienti)
4. Utente accetta → POST /api/richieste/converti/{id}
↓
5. RichiesteConversioneService.convertiRichiestaInImmobile()
- Crea entità Immobili da Richieste
- Migra Valutazioni: richiesta_id → immobile_id
- Mantiene Richieste visibile (PersonalArea)
↓
6. Output: ImmobiliDTO (immobile permanente con valutazione)
Dettagli tecnici:
richiesta_ideimmobile_idsono mutuamente esclusivi nella tabellavalutazioni- Conversione = migrazione, non duplicazione (update, non insert)
- Richieste originale non viene eliminata (tracciabilità storico utente)
# Dalla root del progetto
cd frontendnpm installQuesto installa:
- React 19.1.1
- React Router DOM 7.9.5
- Vite 7.1.7
- Tailwind CSS 3.4.18
- ESLint (linting)
Tempo stimato: 1-3 minuti (prima volta)
File: frontend/vite.config.js
export default defineConfig({
plugins: [react()],
server: {
proxy: {
'/api': {
target: 'http://localhost:8080', // Backend URL
changeOrigin: true,
}
}
}
})Questo permette di chiamare /api/... senza CORS errors, reindirizzando a http://localhost:8080/api/...
Il frontend è una Single Page Application (SPA) costruita con:
| Tecnologia | Versione | Funzione |
|---|---|---|
| React | 19.1.1 | Framework UI con componenti riutilizzabili |
| React Router DOM | 7.9.5 | Routing client-side e navigazione SPA |
| Vite | 7.1.7 | Build tool ultra-veloce con HMR |
| Tailwind CSS | 3.4.18 | Framework CSS utility-first |
| ESLint | 9.36.0 | Linting e code quality |
src/
├── App.jsx # Router principale + lazy loading
├── main.jsx # Entry point applicazione
│
├── Contexts/
│ └── AuthContext.jsx # Gestione autenticazione globale
│
├── Layout/
│ └── Layout.jsx # Wrapper con Navbar + Footer
│
├── pages/ # Pagine principali (route)
│ ├── Home.jsx # Homepage con hero + CTA
│ ├── Search.jsx # Ricerca immobili con filtri
│ ├── PropertyDetail.jsx # Dettaglio singolo immobile
│ ├── Configurator.jsx # Form multi-step valutazione
│ ├── PersonalArea.jsx # Area utente + richieste
│ ├── Backoffice.jsx # Pannello admin (richiede ruolo)
│ ├── Login.jsx # Autenticazione sessione
│ ├── Signin.jsx # Registrazione nuovo utente
│ └── NotFound.jsx # Pagina 404
│
├── components/ # Componenti riutilizzabili
│ ├── navbar.jsx # Header navigazione + auth status
│ ├── Footer.jsx # Footer informazioni
│ ├── ScrollTop.jsx # Auto-scroll top route change
│ │
│ ├── ComponentStep1-6.jsx # Step form valutazione
│ ├── ComponentSummary.jsx # Riepilogo pre-invio
│ │
│ ├── PropertyCard.jsx # Card immobile (griglia)
│ ├── PropertyList.jsx # Lista immobili
│ ├── FiltersSidebar.jsx # Filtri ricerca avanzata
│ │
│ ├── FeaturedProperties.jsx # Immobili in evidenza
│ ├── SearchByCity.jsx # Ricerca per città
│ ├── AgentsSection.jsx # Sezione agenti
│ ├── MissionSection.jsx # Mission aziendale
│ ├── WhyChoose.jsx # Vantaggi competitivi
│ └── NewsLetter.jsx # Iscrizione newsletter
│
└── styles/ # CSS custom per pagine
├── backoffice_tailwind.css
├── configurator_tailwind.css
├── navbar_tailwind.css
├── personalArea_tailwind.css
├── propertyDetails_tailwind.css
└── search_tailwind.css
File: src/Contexts/AuthContext.jsx
Funzionalità:
- Gestione stato utente autenticato (email, ruolo, dati personali)
- Persistenza sessione via cookie HTTP-only (no JWT, sicurezza backend)
- Metodi:
login(),logout(),checkAuth() - Auto-verifica sessione al mount componente
Utilizzo:
import { useAuthContext } from "./Contexts/AuthContext.jsx";
function MyComponent() {
const { user, isAuthenticated, login, logout } = useAuthContext();
if (!isAuthenticated) return <Navigate to="/login" />;
return <h1>Ciao {user.nome}!</h1>;
}Vantaggi:
- Evita prop drilling: stato globale accessibile ovunque
- Single source of truth: un solo posto per auth state
- Persistenza automatica: ricarica pagina preserva sessione
File: src/App.jsx
Implementa protezione route basata su autenticazione e ruolo:
// Richiede autenticazione
<Route
path="/personal-area"
element={isAuthenticated ? <PersonalArea /> : <Navigate to="/login" />}
/>
// Richiede ruolo admin
<Route
path="/backoffice"
element={
!isAuthenticated ? <Navigate to="/login" /> :
user?.role !== "admin" ? <Navigate to="/" /> :
<Backoffice />
}
/>Protezioni implementate:
/personal-area: Solo utenti autenticati/backoffice: Solo admin (verifica doppia: auth + ruolo)
File: src/App.jsx
Tutte le pagine sono caricate on-demand per ottimizzare performance:
import { Suspense, lazy } from "react";
const Home = lazy(() => import("./pages/Home"));
const Search = lazy(() => import("./pages/Search"));
const Backoffice = lazy(() => import("./pages/Backoffice"));
<Suspense fallback={<LoadingScreen />}>
<Routes>
<Route path="/" element={<Home />} />
{/* ... */}
</Routes>
</Suspense>Vantaggi:
- Bundle size ridotto: ogni pagina è un chunk separato
- First Load veloce: carica solo Home, non tutto
- UX migliorata: LoadingScreen durante fetch chunk
Pagina: src/pages/Configurator.jsx
Form multi-step wizard per raccogliere dati immobile e inviare richiesta valutazione.
Step:
- Tipo immobile: Appartamento, Villa, Ufficio, etc.
- Posizione: Indirizzo, CAP, Città, Provincia
- Caratteristiche: Superficie, stanze, bagni, piano
- Dettagli: Anno costruzione, stato conservazione, classe energetica
- Optional: Balcone, garage, giardino, ascensore
- Dati contatto: Nome, cognome, email, telefono
- Summary: Riepilogo completo pre-invio
State management:
const [step, setStep] = useState(1); // Step corrente (1-7)
const [formData, setFormData] = useState({
tipoImmobile: "", indirizzo: "", cap: "",
superficie: "", stanze: "", bagni: "",
nome: "", email: "", telefono: "",
// ... 20+ campi totali
});
const updateField = (field, value) => {
setFormData(prev => ({ ...prev, [field]: value }));
};Invio dati:
const handleSubmit = async () => {
const res = await fetch("/api/richieste", {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify(formData),
});
// Toast successo → redirect homepage
};Backend endpoint: POST /api/richieste
Salva in: Tabella richieste (stato: valutata = false)
Pagina: src/pages/Backoffice.jsx (998 righe, componente complesso)
Sezioni:
-
Aggiungi Immobile
- Form completo per inserimento manuale
- Upload multiplo immagini (FormData multipart)
- Validazione campi obbligatori
- Endpoint:
POST /api/immobili+POST /api/immobili/{id}/immagini
-
Valutazioni Richieste
- Lista richieste valutazione utenti
- Stato visivo: Non valutata | Valutata
- Valutazione automatica: Click bottone → calcolo prezzo basato su
zone_prezzi - Endpoint:
POST /api/richieste/valuta/{id} - Conversione in immobile: Trasforma richiesta in immobile vendibile
- Endpoint:
POST /api/richieste/converti/{id}
-
Modifica Immobili
- Lista immobili esistenti
- Edit inline: titolo, prezzo, descrizione, stato
- Gestione immagini: aggiungi/elimina
- Endpoint:
PUT /api/immobili/{id},DELETE /api/immobili/{id}
Funzionalità avanzate:
- Accordion espandibili: apri/chiudi dettagli immobile
- Modal di conferma custom: evita
window.confirm()nativo - Toast successo: feedback visivo operazioni
- Mobile responsive: sidebar collassabile, layout adattivo
Pagina: src/pages/Search.jsx
Filtri avanzati:
const [filters, setFilters] = useState({
citta: "Tutte",
tipoImmobile: "Tutti",
prezzoMin: "",
prezzoMax: "",
superficieMin: "",
superficieMax: "",
numeroLocali: "",
stato: "Tutti",
});Logica filtraggio:
useEffect(() => {
let filtered = [...allProperties];
if (filters.citta !== "Tutte")
filtered = filtered.filter(p => p.citta === filters.citta);
if (filters.prezzoMin)
filtered = filtered.filter(p => p.prezzoRichiesto >= filters.prezzoMin);
// ... altri filtri
setFilteredProperties(filtered);
}, [filters, allProperties]);Componenti:
FiltersSidebar: Form filtri con resetPropertyList: Griglia card immobiliPropertyCard: Preview con immagine, prezzo, dettagli
Pagina: src/pages/PersonalArea.jsx
Funzionalità:
-
Dati utente:
- Visualizzazione: nome, email, telefono
- Modifica email (inline edit)
- Endpoint:
PUT /api/users/{id}
-
Storico richieste:
- Lista richieste valutazione inviate
- Filtro: Tutte | Valutate | Non valutate
- Visualizza valutazione: Modal con prezzo min/max, coefficienti
- Endpoint:
GET /api/users/{email}/richieste,GET /api/valutazioni/richiesta/{id}
Stato valutazione:
- Non valutata: admin non ha ancora calcolato
- Valutata: mostra bottone "Visualizza Valutazione"
File: vite.config.js
server: {
proxy: {
"/api": {
target: "http://localhost:8080",
changeOrigin: true,
}
}
}Vantaggio: Evita CORS. Frontend chiama /api/immobili, Vite reindirizza a http://localhost:8080/api/immobili.
Esempio standard:
const [data, setData] = useState([]);
const [loading, setLoading] = useState(true);
useEffect(() => {
async function fetchData() {
try {
const res = await fetch("/api/immobili");
const json = await res.json();
setData(json);
} catch (err) {
console.error(err);
} finally {
setLoading(false);
}
}
fetchData();
}, []);Con autenticazione (cookies):
const res = await fetch("/api/auth/me", {
method: "GET",
credentials: "include", // Invia cookie sessione
});File: src/App.jsx
Route principali:
| Path | Componente | Accesso | Descrizione |
|---|---|---|---|
/ |
Home |
Pubblico | Homepage landing |
/cerca |
Search |
Pubblico | Ricerca immobili con filtri |
/immobile/:id |
PropertyDetail |
Pubblico | Dettaglio immobile |
/valuta |
Configurator |
Pubblico | Form valutazione multi-step |
/login |
Login |
Pubblico | Autenticazione |
/signin |
Signin |
Pubblico | Registrazione |
/personal-area |
PersonalArea |
Autenticato | Area utente + richieste |
/backoffice |
Backoffice |
Admin only | Gestione immobili e valutazioni |
* |
NotFound |
Pubblico | Pagina 404 |
Navigazione programmatica:
import { useNavigate } from "react-router-dom";
const navigate = useNavigate();
navigate("/personal-area"); // Redirect dopo loginConfigurazione: tailwind.config.js
Palette colori progetto:
--primary-blue: #004E98 /* Blu aziendale */
--accent-orange: #FF6700 /* Arancione CTA */
--neutral-gray: #EBEBEB /* Grigio background */Pattern comuni:
// Card immobile
<div className="bg-white rounded-xl shadow-lg overflow-hidden hover:shadow-2xl transition-shadow">
// Bottone primario
<button className="bg-[#004E98] text-white px-6 py-3 rounded-lg hover:bg-[#003A73] transition-colors">
// Gradient background
<div style={{ background: 'linear-gradient(135deg, #004E98 0%, #3A6EA5 50%, #5B8DB8 100%)' }}>Organizzazione:
App.css: Stili globali, resetindex.css: Tailwind imports + custom utilitiesstyles/*.css: Override specifici per pagine complesse
Esempio (configurator_tailwind.css):
.configurator {
@apply min-h-screen flex items-center justify-center p-4;
}
.step-card {
@apply bg-white rounded-2xl shadow-xl p-8 max-w-2xl w-full;
}- Lazy Loading Routes: Riduce bundle iniziale da ~800KB a ~200KB
- Image Optimization: Immagini caricate da
/api/immobili/{id}/immagini(backend serve statico) - Debounce Filters: Evita re-render eccessivi durante digitazione filtri
- Memoization:
useMemoper calcoli pesanti (es. filtri complessi) - Code Splitting: Ogni pagina = chunk separato Vite
{loading ? (
<div className="flex justify-center py-20">
<div className="spinner"></div>
</div>
) : (
<PropertyList properties={data} />
)}<Route path="*" element={<NotFound />} />const [showSuccess, setShowSuccess] = useState(false);
// Mostra 3s poi chiudi
setShowSuccess(true);
setTimeout(() => setShowSuccess(false), 3000);✅ Component Composition: Componenti piccoli, riutilizzabili
✅ Separation of Concerns: Logica (pages) vs presentazione (components)
✅ Single Responsibility: Ogni componente ha un compito specifico
✅ DRY Principle: Evita duplicazione (es. PropertyCard riusato in Search/Home)
✅ Controlled Components: Form gestiti via useState
✅ Accessibility: Semantic HTML, ARIA labels, keyboard navigation
✅ Mobile First: Design responsive, sidebar collassabile
✅ Performance: Lazy loading, code splitting, immagini ottimizzate
- Backend (prima)
- Frontend (dopo che il backend è online)
Opzione A: Da Terminale (Maven)
# Dalla cartella backend/
cd backend
# Con Maven installato
mvn spring-boot:run
# OPPURE con Maven Wrapper
.\mvnw.cmd spring-boot:run # Windows PowerShell
./mvnw spring-boot:run # macOS/LinuxOpzione B: Da Terminale (JAR diretto)
# Prima compila (se non fatto)
mvn clean package -DskipTests
# Poi esegui il JAR
java -jar target/backend-0.0.1-SNAPSHOT.jarOpzione C: Da IDE (IntelliJ / Eclipse / VS Code)
- Apri il progetto
backend/nell'IDE - Trova la classe
BackendApplication.java - Click destro → Run 'BackendApplication'
Output atteso:
. ____ _ __ _ _
/\\ / ___'_ __ _ _(_)_ __ __ _ \ \ \ \
( ( )\___ | '_ | '_| | '_ \/ _` | \ \ \ \
\\/ ___)| |_)| | | | | || (_| | ) ) ) )
' |____| .__|_| |_|_| |_\__, | / / / /
=========|_|==============|___/=/_/_/_/
...
Started BackendApplication in 3.456 seconds (process running for 4.123)
Backend online su: http://localhost:8080
Apri un NUOVO terminale (lascia il backend in esecuzione)
# Dalla root del progetto
cd frontend
# Avvia server di sviluppo Vite
npm run devOutput atteso:
VITE v7.1.7 ready in 234 ms
➜ Local: http://localhost:5173/
➜ Network: use --host to expose
➜ press h + enter to show help
Frontend online su: http://localhost:5173
- Assicurati che il backend sia in esecuzione
- Apri browser e vai a: http://localhost:8080/h2
Inserisci nel form di login:
| Campo | Valore |
|---|---|
| JDBC URL | jdbc:h2:file:./data/immobiliaris |
| User Name | sa |
| Password | (lascia vuoto) |
Click su Connect
Ora puoi:
- Vedere le 9 tabelle:
users,immobili,richieste,valutazioni,zone_prezzi, ecc. - Eseguire query SQL:
SELECT * FROM users; SELECT * FROM zone_prezzi WHERE citta = 'Torino'; SELECT * FROM valutazioni WHERE richiesta_id IS NOT NULL;
users
id, nome, cognome, email (UNIQUE), password, telefono,
ruolo ('utente'|'admin'), data_registrazione, verificatoimmobili
id, proprietario_id (FK→users), tipo_immobile, indirizzo,
citta, cap, superficie, num_locali, prezzo_richiesto,
stato ('bozza'|'valutato'|'in_vendita'|'venduto'), ...richieste
id, nome, cognome, email, telefono, tipo_immobile,
superficie, cap, stato_conservazione, classe_energetica,
valutata (BOOLEAN), data_creazione, ...valutazioni TABELLA IBRIDA
id,
immobile_id (FK→immobili, NULLABLE), -- NULL se valutazione per richiesta
richiesta_id (FK→richieste, NULLABLE), -- NULL se valutazione per immobile
valore_stimato_min, valore_stimato_max,
prezzo_mq, note, data_valutazionezone_prezzi
id, cap (UNIQUE), citta, zona_nome, prezzo_mq_medio
-- 48 zone Piemonte (Torino: 36 CAP, altre città: 12)Metodo A: Browser
Apri browser e testa questi endpoint:
GET http://localhost:8080/api/immobili
→ Lista immobili (JSON)
GET http://localhost:8080/api/zone-prezzi
→ Lista zone prezzi Piemonte
GET http://localhost:8080/api/auth/check
→ Verifica sessione (risponde sempre, anche non autenticato)
Metodo B: PowerShell
# Test endpoint immobili
Invoke-RestMethod -Uri 'http://localhost:8080/api/immobili' -Method Get
# Test endpoint zone prezzi
Invoke-RestMethod -Uri 'http://localhost:8080/api/zone-prezzi' -Method GetMetodo C: VS Code Extension (REST Client / Thunder Client)
- Installa estensione REST Client o Thunder Client
- Crea file
test.http:### Get all immobili GET http://localhost:8080/api/immobili ### Get zone prezzi GET http://localhost:8080/api/zone-prezzi
- Click su "Send Request"
- Apri browser: http://localhost:5173
- Dovresti vedere la Homepage di Immobiliaris
- Naviga:
- Configuratore:
/configurator(form multi-step valutazione) - Login:
/login - Ricerca Immobili:
/search - Backoffice:
/backoffice(richiede login admin)
- Configuratore:
- Vai a: http://localhost:5173/login
- Credenziali di test:
Email: andrea.verdi@email.com Password: 1234 - Dopo login, puoi accedere a
/backofficeper gestire richieste
Scenario: Utente richiede valutazione immobile
- Frontend →
/configurator - Compila form multi-step:
- Dati personali
- Indirizzo + CAP (es.
10121Torino) - Caratteristiche (superficie, stanze, classe energetica)
- Invia form → crea record in tabella
richieste - Backoffice (
/backofficecome admin):- Vedi richiesta nella lista
- Click "Valuta automaticamente"
- Sistema calcola valore basandosi su
zone_prezzi+ modificatori - Salva in tabella
valutazioniconrichiesta_id - Flag
richieste.valutata = TRUE(pallino verde)
- Database H2 → verifica record:
SELECT * FROM richieste WHERE valutata = TRUE; SELECT * FROM valutazioni WHERE richiesta_id IS NOT NULL;
Il sistema può inviare email transazionali tramite Brevo (ex Sendinblue).
- Registrati su: https://www.brevo.com
- Vai a: Settings → API Keys
- Crea una nuova chiave (tipo:
Transactional Emails) - Copia la chiave (es.
xkeysib-abc123...)
application.properties o committarla su Git!
Windows PowerShell:
$env:BREVO_API_KEY = "xkeysib-TUA_CHIAVE_QUI"macOS/Linux:
export BREVO_API_KEY="xkeysib-TUA_CHIAVE_QUI"Permanente (Windows):
- Cerca "Variabili d'ambiente" nel menu Start
- Variabili d'ambiente → Nuova (utente)
- Nome:
BREVO_API_KEY - Valore:
xkeysib-TUA_CHIAVE_QUI
File: application.properties
brevo.api.key=${BREVO_API_KEY:}
brevo.sender.email=noreply@tuodominio.com
brevo.sender.name=ImmobiliarisEndpoint: POST /api/email/send
Payload:
{
"to": "destinatario@example.com",
"name": "Mario Rossi",
"subject": "Test Email",
"text": "Corpo del messaggio"
}PowerShell:
$json = '{"to":"tua-email@example.com","name":"Test","subject":"Prova","text":"Funziona!"}'
$bytes = [System.Text.Encoding]::UTF8.GetBytes($json)
Invoke-RestMethod -Uri 'http://localhost:8080/api/email/send' -Method Post -ContentType 'application/json' -Body $bytesDocumentazione completa: Vedi sezione successiva (Capitolo 11)
Brevo (ex Sendinblue) è la piattaforma di email marketing integrata nel progetto per:
- Email transazionali: conferma richiesta valutazione, notifiche
- Campagne marketing: newsletter, promozioni immobili
- Gestione contatti: liste utenti, segmentazione
File coinvolti:
backend/src/main/java/com/immobiliaris/backend/service/BrevoEmailService.javabackend/src/main/java/com/immobiliaris/backend/controller/EmailController.javabackend/src/main/resources/application.properties(variabileBREVO_API_KEY)
- Registrati su Brevo
- Vai su Impostazioni → API Keys
- Genera nuova chiave (copia subito, mostrata una sola volta)
PowerShell (Windows):
# Sessione corrente
$env:BREVO_API_KEY = "tua-chiave-api-brevo"
# Persistente (richiede riavvio terminale)
[System.Environment]::SetEnvironmentVariable('BREVO_API_KEY', 'tua-chiave-api', 'User')Bash (macOS/Linux):
# Sessione corrente
export BREVO_API_KEY="tua-chiave-api-brevo"
# Persistente (aggiungi a ~/.bashrc o ~/.zshrc)
echo 'export BREVO_API_KEY="tua-chiave-api"' >> ~/.bashrc
source ~/.bashrcVerifica configurazione:
echo $env:BREVO_API_KEY # PowerShell
echo $BREVO_API_KEY # BashGET http://localhost:8080/api/brevo/statusRisposta:
{
"status": "connected",
"apiKeyConfigured": true,
"accountName": "Immobiliaris"
}POST http://localhost:8080/api/email/send
Content-Type: application/json
{
"to": "destinatario@example.com",
"name": "Mario Rossi",
"subject": "Conferma Richiesta Valutazione",
"text": "Grazie per la tua richiesta. La valuteremo entro 72 ore.",
"listIds": [3]
}Parametri:
to(string, required): Email destinatarioname(string, required): Nome destinatariosubject(string, required): Oggetto emailtext(string, required): Corpo messaggio plain texttemplateId(integer, optional): ID template Brevoparams(object, optional): Variabili per templatelistIds(array, optional): Aggiungi contatto a liste
Risposta:
{
"messageId": "abc123...",
"success": true
}Per operazioni avanzate, chiama direttamente le API Brevo:
Base URL: https://api.brevo.com/v3
Header richiesti:
api-key: YOUR_API_KEYContent-Type: application/json
curl -X GET "https://api.brevo.com/v3/contacts" \
-H "api-key: tua-chiave-api" \
-H "Content-Type: application/json"curl -X POST "https://api.brevo.com/v3/contacts" \
-H "api-key: tua-chiave-api" \
-H "Content-Type: application/json" \
-d '{
"email": "user@example.com",
"attributes": {
"FIRSTNAME": "Mario",
"LASTNAME": "Rossi"
},
"listIds": [3],
"updateEnabled": true
}'curl -X GET "https://api.brevo.com/v3/contacts/{contactId}" \
-H "api-key: tua-chiave-api"curl -X GET "https://api.brevo.com/v3/emailCampaigns" \
-H "api-key: tua-chiave-api"curl -X POST "https://api.brevo.com/v3/emailCampaigns" \
-H "api-key: tua-chiave-api" \
-H "Content-Type: application/json" \
-d '{
"name": "Nuovi Immobili Marzo",
"subject": "Scopri le nuove proprietà disponibili",
"sender": {
"name": "Immobiliaris",
"email": "info@immobiliaris.it"
},
"type": "classic",
"htmlContent": "<h1>Nuovi immobili in esclusiva</h1>...",
"listIds": [3]
}'curl -X POST "https://api.brevo.com/v3/emailCampaigns/{campaignId}/sendNow" \
-H "api-key: tua-chiave-api"curl -X POST "https://api.brevo.com/v3/smtp/email" \
-H "api-key: tua-chiave-api" \
-H "Content-Type: application/json" \
-d '{
"sender": {
"name": "Immobiliaris",
"email": "noreply@immobiliaris.it"
},
"to": [
{
"email": "user@example.com",
"name": "Mario"
}
],
"subject": "Conferma richiesta",
"textContent": "Grazie per la tua richiesta..."
}'Passo 1: Installa estensione Thunder Client
Passo 2: Crea nuova richiesta
- Method:
POST - URL:
http://localhost:8080/api/email/send - Headers:
Content-Type: application/json
- Body (raw JSON):
{
"to": "tua-email@example.com",
"name": "Test User",
"subject": "Test Invio",
"text": "Questo è un messaggio di test",
"listIds": [3]
}Passo 3: Clicca Send → verifica risposta
# Prepara JSON payload
$json = @'
{
"to": "tua-email@example.com",
"name": "Test User",
"subject": "Test PowerShell",
"text": "Email inviata da PowerShell",
"listIds": [3]
}
'@
# Converti in bytes UTF-8 (evita problemi encoding)
$bytes = [System.Text.Encoding]::UTF8.GetBytes($json)
# Invia richiesta
Invoke-RestMethod -Uri 'http://localhost:8080/api/email/send' `
-Method Post `
-ContentType 'application/json' `
-Body $bytesMessaggio: "Unable to send email. Your SMTP account is not yet activated..."
Causa: Account Brevo non abilitato per invii transazionali (limitazione nuovo account)
Soluzione:
- Contatta supporto Brevo via email:
Subject: Activate Transactional Email Account Hello, I need to enable transactional emails for my account. Account email: tuo-email@example.com Use case: Real estate platform confirmation emails Thanks, [Tuo Nome] - Attendi conferma (solitamente 24-48h)
- Verifica status con
GET /api/brevo/status
Causa: Credenziali SMTP errate (se usi relay SMTP invece di API)
Soluzione:
- Vai su pannello Brevo → SMTP & API
- Rigenera password SMTP
- Aggiorna credenziali in
application.properties:spring.mail.username=tuo-username@brevo.com spring.mail.password=nuova-password-smtp
Causa: Encoding caratteri speciali non gestito
Soluzione: Usa conversione bytes UTF-8 (vedi esempio PowerShell sopra)
Messaggio: 429 Too Many Requests
Causa: Piano gratuito Brevo limita invii (es. 300/giorno)
Soluzione:
- Verifica limiti nel pannello Brevo
- Upgrade piano (Starter: 20.000 email/mese)
- Implementa throttling nel backend con
@RateLimiter
❌ MAI fare:
- Committare
BREVO_API_KEYinapplication.properties - Condividere chiave in chat/forum pubblici
- Usare stessa chiave per dev/staging/produzione
✅ Best Practices:
- Usa variabili ambiente (
$env:BREVO_API_KEY) - Produzione: secret manager (AWS Secrets, Azure Key Vault)
- Rigenera chiave se compromessa
- Chiavi diverse per ambiente (dev/staging/prod)
- Log: censura chiavi (
***invece del valore)
Causa: Un altro processo usa la porta 8080
Soluzione Windows:
# Trova processo sulla porta 8080
netstat -ano | findstr :8080
# Termina processo (sostituisci PID)
taskkill /PID <numero_pid> /FSoluzione alternativa: Cambia porta in application.properties:
server.port=8081Causa: Dipendenze npm non installate
Soluzione:
cd frontend
npm installCausa: Frontend chiama backend senza proxy configurato
Soluzione: Verifica frontend/vite.config.js:
server: {
proxy: {
'/api': {
target: 'http://localhost:8080',
changeOrigin: true,
}
}
}Riavvia Vite: Ctrl+C → npm run dev
Causa: JDBC URL errato
Soluzione: Nella console H2, usa esattamente:
jdbc:h2:file:./data/immobiliaris
(NON ~/data/immobiliaris o C:\...)
Causa: Java versione diversa da 21
Soluzione:
# Verifica versione
java -version
# Se diversa da 21, scarica JDK 21 e imposta JAVA_HOME
$env:JAVA_HOME = "C:\Program Files\Java\jdk-21"
$env:PATH = "$env:JAVA_HOME\bin;$env:PATH"Causa: Cache corrotta o dipendenze non scaricate
Soluzione:
# Pulisci cache Maven
mvn clean
# Forza download dipendenze
mvn clean install -U
# Se fallisce ancora, elimina cache locale
Remove-Item -Recurse -Force ~\.m2\repository
mvn clean installIn caso di problemi non risolvibili, contatta i membri del team per area di competenza:
- Omar Benagoub - @Omarben05
- Domenico Vardé - @domenicovarde
- Simone Pizzorno - @Simone-Pix
- Vittorio Cenni - @ViTz1
- Andrea Giraudo - @AndreaXVII17
- Mayté Cachi - @MayteCachi
- Ilaria Mussano - @ilariamussano-cyber
- Saverio Chiusolo - @saveriochiusolo-cell
- Tommaso Allietta - @tommasoallietta-beep
Repository GitHub: Simone-Pix/Connectwork
- Java 21 installato (
java -version) - Maven funzionante (
mvn -versionomvnw) - Node.js 20+ installato (
node -v) - Repository clonato correttamente
- Backend: dipendenze scaricate (
mvn clean install) - Frontend: dipendenze scaricate (
npm install) - Backend avviato senza errori (porta 8080)
- Frontend avviato senza errori (porta 5173)
- Console H2 accessibile (
http://localhost:8080/h2) - Homepage visibile (
http://localhost:5173) - Login admin funzionante (
andrea.verdi@email.com/1234) - Endpoint API rispondono (
/api/immobili,/api/zone-prezzi) - (Opzionale) Brevo API key configurata
Installazione Completata!
Il progetto Immobiliaris è ora pronto per lo sviluppo o il testing.
Per avviare il progetto in futuro:
- Apri 2 terminali
- Terminale 1:
cd backend→mvn spring-boot:run - Terminale 2:
cd frontend→npm run dev - Apri browser:
http://localhost:5173
Buon lavoro!