Creo applicazioni web moderne e strumenti digitali personalizzati per aiutare le attività a crescere attraverso l'innovazione tecnologica. La mia passione è unire informatica ed economia per generare valore reale.
La mia passione per l'informatica è nata tra i banchi dell'Istituto Tecnico Commerciale di Maglie, dove ho scoperto il potere della programmazione e il fascino di creare soluzioni digitali. Fin da subito, ho capito che l'informatica non era solo codice, ma uno strumento straordinario per trasformare idee in realtà.
Durante gli studi superiori in Sistemi Informativi Aziendali, ho iniziato a intrecciare informatica ed economia, comprendendo come la tecnologia possa essere il motore della crescita per qualsiasi attività. Questa visione mi ha accompagnato all'Università degli Studi di Bari, dove ho conseguito la Laurea in Informatica, approfondendo le mie competenze tecniche e la mia passione per lo sviluppo software.
Oggi metto questa esperienza al servizio di imprese, professionisti e startup, creando soluzioni digitali su misura che automatizzano processi, ottimizzano risorse e aprono nuove opportunità di business. Perché la vera innovazione inizia quando la tecnologia incontra le esigenze reali delle persone.
Le Mie Competenze
Analisi Dati & Modelli Previsionali
Trasformo i dati in insights strategici con analisi approfondite e modelli predittivi per decisioni informate
Automazione Processi
Creo strumenti personalizzati che automatizzano operazioni ripetitive e liberano tempo per attività a valore aggiunto
Sistemi Custom
Sviluppo sistemi software su misura, dalle integrazioni tra piattaforme alle dashboard personalizzate
Credo fermamente che l'informatica sia lo strumento più potente per trasformare le idee in realtà e migliorare la vita delle persone.
🚀
Democratizzare la Tecnologia
La mia missione è rendere l'informatica accessibile a tutti: dalle piccole imprese locali alle startup innovative, fino ai professionisti che vogliono digitalizzare la propria attività. Ogni realtà merita di sfruttare le potenzialità del digitale.
💡
Unire Informatica ed Economia
Non è solo questione di scrivere codice: è capire come la tecnologia possa generare valore reale. Intrecciando competenze informatiche e visione economica, aiuto le attività a crescere, ottimizzare processi e raggiungere nuovi traguardi di efficienza e redditività.
🎯
Creare Soluzioni su Misura
Ogni attività è unica, e così devono esserlo le soluzioni. Sviluppo strumenti personalizzati che rispondono alle esigenze specifiche di ciascun cliente, automatizzando processi ripetitivi e liberando tempo per ciò che conta davvero: far crescere il business.
Trasforma la Tua Attività con la Tecnologia
Che tu gestisca un negozio, uno studio professionale o un'azienda, posso aiutarti a sfruttare le potenzialità dell'informatica per lavorare meglio, più velocemente e in modo più intelligente.
Il mio percorso accademico e le tecnologie che padroneggio
Certificazioni Professionali
8 certificazioni conseguite
Nuovo
Visualizza
Reinvention With Agentic AI Learning Program
Anthropic
Dicembre 2024
Nuovo
Visualizza
Agentic AI Fluency
Anthropic
Dicembre 2024
Nuovo
Visualizza
AI Fluency for Students
Anthropic
Dicembre 2024
Nuovo
Visualizza
AI Fluency: Framework and Foundations
Anthropic
Dicembre 2024
Nuovo
Visualizza
Claude with the Anthropic API
Anthropic
Dicembre 2024
Visualizza
Master SQL
RoadMap.sh
Novembre 2024
Visualizza
Oracle Certified Foundations Associate
Oracle
Ottobre 2024
Visualizza
People Leadership Credential
Connect
Settembre 2024
💻 Linguaggi & Tecnologie
☕Java
🐍Python
📜JavaScript
🅰️Angular
⚛️React
🔷TypeScript
🗄️SQL
🐘PHP
🎨CSS/SCSS
🔧Node.js
🐳Docker
🌿Git
💼
12/2024 - Presente
Custom Software Engineering Analyst
Accenture
Bari, Puglia, Italia · Ibrida
Analisi e sviluppo di sistemi informatici attraverso l'utilizzo di Java e Quarkus in Health and Public Sector. Formazione continua su tecnologie moderne per la creazione di soluzioni software personalizzate ed efficienti e sugli agenti.
💼
06/2022 - 12/2024
Analista software e Back End Developer Associate Consultant
Links Management and Technology SpA
Esperienza nell'analisi di sistemi software as-is e flussi ETL utilizzando PowerCenter. Formazione completata su Spring Boot per lo sviluppo di applicazioni backend moderne e scalabili. Sviluppatore Backend specializzato in Spring Boot, con esperienza in progettazione di database, analisi, sviluppo e testing dei task assegnati.
💼
02/2021 - 10/2021
Programmatore software
Adesso.it (prima era WebScience srl)
Esperienza nell'analisi AS-IS e TO-BE, evoluzioni SEO ed evoluzioni website per migliorare le performance e l'engagement degli utenti.
🎓
2018 - 2025
Laurea in Informatica
Università degli Studi di Bari Aldo Moro
Bachelor's degree in Computer Science, focusing on software engineering, algorithms, and modern development practices.
📚
2013 - 2018
Diploma - Sistemi Informativi Aziendali
Istituto Tecnico Commerciale di Maglie
Technical diploma specializing in Business Information Systems, combining IT knowledge with business management.
Contattami
Hai un progetto in mente? Parliamone! Compila il form qui sotto e ti risponderò al più presto.
* Campi obbligatori. I tuoi dati saranno utilizzati solo per rispondere alla tua richiesta.
Mobile-First EdTech: Offline-First Architecture
67% of students in developing countries access educational content exclusively via smartphone,
often with unstable 2G/3G connections or no connectivity at all. Even in advanced economies,
commuters, students in rural areas, and those studying in low-WiFi locations face the same
challenges. An EdTech platform that requires constant connectivity is a platform that excludes
a significant portion of its audience.
Offline-first architecture flips the traditional paradigm: instead of
"online by default, offline as an exception," it becomes "offline by default, online for
synchronization." The app always works, immediately, even without internet.
When connectivity is available, it syncs data in the background.
Research from 2025 shows that offline-first apps have 40% higher engagement
and 25% lower bounce rates compared to network-first apps.
In this article we will build the complete architecture of an offline-first EdTech
Progressive Web App (PWA): Service Workers for caching, IndexedDB for local storage,
sync strategies with conflict resolution, and intelligent content pre-fetching
for continuous learning.
What You Will Learn
Service Worker caching strategies: cache-first, network-first, stale-while-revalidate
IndexedDB for structured client-side storage with Dexie.js
Repository pattern for separating UI from network/storage
Background Sync API for reliable synchronization
Conflict resolution for offline modifications
Intelligent content pre-fetching based on curriculum
Offline progress tracking: xAPI statement queue
Push notifications for study recall
1. Offline-First Architecture: The Repository Pattern
The fundamental principle of offline-first is the Repository Pattern:
UI components never talk directly to the network. They interact with a
repository that transparently manages caching logic:
reads first from the local cache (instant response), then syncs with the server
in the background (silent update). The user never waits for the network.
The Service Worker is the heart of offline-first. It intercepts all HTTP requests and
decides how to respond: from cache, from the network, or a combination.
For an EdTech platform we use different strategies for different resource types.
// src/service-worker.ts (Workbox-based)
import { precacheAndRoute, cleanupOutdatedCaches } from 'workbox-precaching';
import { registerRoute, NavigationRoute } from 'workbox-routing';
import { CacheFirst, NetworkFirst, StaleWhileRevalidate, NetworkOnly } from 'workbox-strategies';
import { CacheableResponsePlugin } from 'workbox-cacheable-response';
import { ExpirationPlugin } from 'workbox-expiration';
import { BackgroundSyncPlugin } from 'workbox-background-sync';
declare const self: ServiceWorkerGlobalScope;
precacheAndRoute(self.__WB_MANIFEST);
cleanupOutdatedCaches();
// 1. Static content (images, fonts): Cache-First, long TTL
registerRoute(
({ request }) => request.destination === 'image' || request.destination === 'font',
new CacheFirst({
cacheName: 'edtech-static-v1',
plugins: [
new CacheableResponsePlugin({ statuses: [0, 200] }),
new ExpirationPlugin({ maxEntries: 200, maxAgeSeconds: 30 * 24 * 60 * 60 }),
],
}),
);
// 2. Course API data: Stale-While-Revalidate
// Instant cache response, silent background update
registerRoute(
({ url }) => url.pathname.startsWith('/api/courses/') && !url.pathname.includes('/progress'),
new StaleWhileRevalidate({
cacheName: 'edtech-api-courses-v1',
plugins: [
new CacheableResponsePlugin({ statuses: [200] }),
new ExpirationPlugin({ maxEntries: 100, maxAgeSeconds: 60 * 60 }),
],
}),
);
// 3. Student profile and progress: Network-First
// Critical to have fresh data, but fallback to cache if offline
registerRoute(
({ url }) => url.pathname.startsWith('/api/students/') || url.pathname.startsWith('/api/progress'),
new NetworkFirst({
cacheName: 'edtech-api-student-v1',
networkTimeoutSeconds: 5,
plugins: [
new CacheableResponsePlugin({ statuses: [200] }),
new ExpirationPlugin({ maxEntries: 50, maxAgeSeconds: 24 * 60 * 60 }),
],
}),
);
// 4. POST progress: Background Sync for reliability
const bgSyncPlugin = new BackgroundSyncPlugin('edtech-progress-sync', {
maxRetentionTime: 7 * 24 * 60, // Retry for 7 days (in minutes)
});
registerRoute(
({ url, request }) => url.pathname.startsWith('/api/progress') && request.method === 'POST',
new NetworkOnly({ plugins: [bgSyncPlugin] }),
'POST',
);
// 5. SPA navigation: Fallback to index.html if offline
registerRoute(new NavigationRoute(new NetworkFirst({ cacheName: 'edtech-shell-v1', networkTimeoutSeconds: 3 })));
3. Intelligent Content Pre-Fetching
It is not enough to respond to offline requests: we must anticipate them.
If a student is watching Lesson 3 of a course, they will likely want Lesson 4 soon.
Intelligent pre-fetching downloads content in the background that the student
will probably want, when connectivity is available, without wasting data.
// src/offline/prefetch.service.ts
import { Injectable, Inject } from '@angular/core';
import { PLATFORM_ID } from '@angular/core';
import { isPlatformBrowser } from '@angular/common';
import { HttpClient } from '@angular/common/http';
import { firstValueFrom } from 'rxjs';
@Injectable({ providedIn: 'root' })
export class ContentPrefetchService {
constructor(
private http: HttpClient,
@Inject(PLATFORM_ID) private platformId: object,
) {}
async prefetchNextLessons(courseId: string, currentId: string, allIds: string[]): Promise<void> {
if (!isPlatformBrowser(this.platformId) || !this.shouldPrefetch()) return;
const idx = allIds.indexOf(currentId);
if (idx === -1) return;
for (const id of allIds.slice(idx + 1, idx + 4)) {
await this.prefetchLesson(id).catch(() => {});
}
}
private async prefetchLesson(lessonId: string): Promise<void> {
const cache = await caches.open('edtech-api-courses-v1');
const url = `/api/lessons/#123;lessonId}`;
if (await cache.match(url)) return;
const response = await fetch(url);
if (response.ok) await cache.put(url, response.clone());
}
private shouldPrefetch(): boolean {
const conn = (navigator as any).connection;
if (!conn) return navigator.onLine;
return navigator.onLine && !conn.saveData && !['slow-2g', '2g'].includes(conn.effectiveType);
}
async getStorageUsage(): Promise<{ used: number; quota: number }> {
if (!('storage' in navigator)) return { used: 0, quota: 0 };
const est = await navigator.storage.estimate();
return { used: Math.round((est.usage ?? 0) / 1024 / 1024), quota: Math.round((est.quota ?? 0) / 1024 / 1024) };
}
}
4. Conflict Resolution for Offline Modifications
When a student modifies their progress offline and then reconnects, there may be a conflict
with server data (e.g., the teacher reset the course progress).
We implement a three-way merge strategy: compare local state, server state,
and the common known state before disconnection.
# server/conflict_resolution.py
from dataclasses import dataclass
from typing import Optional, Dict, Any
from enum import Enum
from datetime import datetime
class ConflictStrategy(Enum):
LOCAL_WINS = "local_wins"
SERVER_WINS = "server_wins"
MERGE = "merge"
@dataclass
class ProgressVersion:
progress: float
completed: bool
time_spent: int
answers: Dict[str, Any]
timestamp: datetime
version: int
@dataclass
class ConflictResult:
strategy_used: ConflictStrategy
resolved_progress: ProgressVersion
conflict_detected: bool
details: str
class ProgressConflictResolver:
"""Three-way merge: local, server, base (common known state)."""
def resolve(self, local: ProgressVersion, server: ProgressVersion, base: Optional[ProgressVersion] = None) -> ConflictResult:
if local.version == server.version:
return ConflictResult(ConflictStrategy.MERGE, local, False, "No conflict: versions match")
if local.progress >= server.progress:
winner, strategy, details = local, ConflictStrategy.LOCAL_WINS, f"Local {local.progress:.1%} >= server {server.progress:.1%}"
else:
winner, strategy, details = server, ConflictStrategy.SERVER_WINS, f"Server {server.progress:.1%} > local {local.progress:.1%}"
merged_time = self._merge_time(local, server, base)
merged_answers = ({**server.answers, **local.answers} if local.timestamp > server.timestamp
else {**local.answers, **server.answers})
resolved = ProgressVersion(
progress=winner.progress,
completed=local.completed or server.completed,
time_spent=merged_time,
answers=merged_answers,
timestamp=max(local.timestamp, server.timestamp),
version=max(local.version, server.version) + 1,
)
return ConflictResult(strategy, resolved, True, details)
def _merge_time(self, local: ProgressVersion, server: ProgressVersion, base: Optional[ProgressVersion]) -> int:
if base is None:
return max(local.time_spent, server.time_spent)
local_delta = max(0, local.time_spent - base.time_spent)
server_delta = max(0, server.time_spent - base.time_spent)
return base.time_spent + local_delta + server_delta
Anti-Patterns to Avoid
Caching everything indiscriminately: Caching sensitive data (grades, personal info) without encryption is a GDPR risk. Encrypt before caching.
Service Worker without versioning: An unversioned cache continues serving stale content after deployment. Use versioned cache names and cleanupOutdatedCaches().
Aggressive pre-fetch on 2G: Pre-fetching consumes student data. Check navigator.connection.effectiveType and respect saveData.
No conflict resolution: Without a merge strategy, offline progress is lost or overwritten on sync. Always implement at least "take the higher progress."
Synchronous IndexedDB operations: IndexedDB is asynchronous. Use Dexie.js to avoid callback hell and properly handle errors.
Service Worker not tested offline: Always test with Chrome DevTools > Network > Offline before deploying. Offline edge cases are hard to debug in production.
Conclusions and Next Steps
We have built a complete offline-first architecture for a mobile EdTech platform:
Repository Pattern to separate UI from storage/network, Service Worker with differentiated
caching strategies per resource type, intelligent pre-fetching respecting connection type,
conflict resolution for offline progress, and Push Notifications for study recall.
The result is a platform that works for all students, regardless of connection quality:
from fiber optic to intermittent 2G, including the subway with no signal.
Learning never stops.
In the final article of the series we will explore multi-tenant content management
with SCORM: how to structure, version, and distribute eLearning content packages
scalable to thousands of organizations.
EdTech Engineering Series
Scalable LMS Architecture: Multi-Tenant Patterns
Adaptive Learning Algorithms: From Theory to Production
Video Streaming for Education: WebRTC vs HLS vs DASH
AI Proctoring Systems: Privacy-First with Computer Vision
Personalized AI Tutor with LLM: RAG for Knowledge Grounding
Gamification Engine: Architecture and State Machine
Learning Analytics: Data Pipeline with xAPI and Kafka
Real-Time Collaboration in EdTech: CRDT and WebSocket