Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
49 changes: 41 additions & 8 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1,16 +1,49 @@
# Python
__pycache__/
*.py[cod]
*$py.class
*.so
.Python
env/
venv/
.env
.venv
instance/
.venv/
pip-log.txt
pip-delete-this-directory.txt
.tox/
.coverage
htmlcov/
dist/
build/
*.egg-info/
.DS_Store
.coverage.*
.cache
nosetests.xml
coverage.xml
*.cover
.hypothesis/
.pytest_cache/

# Flask
instance/
.webassets-cache

# IDEs
.vscode/
.idea/
*.swp
*.swo
*~
.DS_Store

# Environment variables
.env
.env.local
.env.*.local

# Logs
*.log

# Database
*.db
*.sqlite
*.sqlite3

# Temporary files
*.tmp
*.bak
132 changes: 132 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,132 @@
# GIST Framework - Digital Maturity Assessment

Web application professionale per la valutazione della maturità digitale nel settore GDO basata sul framework GIST.

## 🎯 Caratteristiche

- ✅ **36 domande strutturate** su 4 dimensioni critiche
- ✅ **Calcolo GIST Score** con formula scientifica validata
- ✅ **Progress bar real-time** e validazione interattiva
- ✅ **Grafici radar e bar chart** per visualizzazione risultati
- ✅ **Raccomandazioni prioritizzate** con ROI stimato
- ✅ **Benchmark settoriale** vs media GDO italiana
- ✅ **Design responsive** con Tailwind CSS
- ✅ **Report dettagliati** con piano d'azione

## 📊 Le 4 Dimensioni GIST

1. **Infrastruttura Fisica (18%)** - Alimentazione, connettività, ridondanza
2. **Architettura (32%)** - Cloud, microservizi, DevOps, API
3. **Sicurezza (28%)** - Identity, network, endpoint, threat detection
4. **Conformità (22%)** - GDPR, PCI-DSS, NIS2, audit

## 🚀 Quick Start - Locale

```bash
# Clona il repository
git clone <your-repo-url>
cd gist-assessment

# Installa dipendenze
pip install -r requirements.txt

# Avvia l'app
python app.py

# Apri browser su http://localhost:5000
```

## ☁️ Deploy su Render

1. **Push del codice su GitHub**
```bash
git init
git add .
git commit -m "Initial commit"
git remote add origin <your-github-repo>
git push -u origin main
```

2. **Configura Render**
- Vai su [render.com](https://render.com)
- New → Web Service
- Connetti repository GitHub
- Configura:
- **Build Command**: `pip install -r requirements.txt`
- **Start Command**: `gunicorn app:app`
- **Environment**: Python 3

3. **Deploy automatico**
- Render farà il deploy automatico ad ogni push su main

## 📁 Struttura Progetto

```
gist-assessment/
├── app.py # Flask application principale
├── gist_calculator.py # GIST Score calculator
├── questionnaire.py # 36 domande strutturate
├── requirements.txt # Dipendenze Python
├── templates/
│ ├── base.html # Template base con navbar
│ ├── index.html # Homepage
│ ├── assessment.html # Questionario interattivo
│ ├── results.html # Pagina risultati con grafici
│ └── about.html # Informazioni framework
└── static/ # (Future: CSS, JS, images custom)
```

## 🎨 Tecnologie Utilizzate

- **Backend**: Flask 3.0
- **Frontend**: Tailwind CSS + Chart.js
- **Grafici**: Chart.js per radar e bar charts
- **Icons**: Font Awesome 6
- **Fonts**: Google Fonts (Inter)
- **Deployment**: Gunicorn + Render

## 📈 Roadmap Futuri Sviluppi

### Fase 2 - Business Features
- [ ] Autenticazione utenti (email/password + OAuth)
- [ ] Database PostgreSQL per storico assessment
- [ ] Email delivery con report PDF
- [ ] Payment gateway Stripe (€49/assessment)

### Fase 3 - Premium Features
- [ ] Generazione PDF professionale con reportlab
- [ ] Comparison tracking nel tempo
- [ ] API pubblica per integrazioni
- [ ] Dashboard amministratore

### Fase 4 - AI & Advanced
- [ ] Raccomandazioni AI-powered personalizzate
- [ ] Predictive analytics
- [ ] Multi-lingua (EN/IT/DE)
- [ ] Mobile app nativa

## 🔬 Validazione Scientifica

Il framework GIST è basato su:
- Ricerca accademica validata su 234 organizzazioni
- Dataset reale settore GDO italiano
- Simulazioni Digital Twin con 10.000 iterazioni
- Intervalli di confidenza al 95%

## 📄 Licenza

MIT License - Open Source

## 👤 Autore

Sviluppato come tesi di laurea magistrale in Cybersecurity
GitHub: [gist-framework](https://github.com/gist-framework)

## 📧 Contatti

Per informazioni commerciali: info@gist-framework.com

---

**Versione**: 1.0.0 (MVP)
**Data**: Ottobre 2025
141 changes: 91 additions & 50 deletions app.py
Original file line number Diff line number Diff line change
@@ -1,60 +1,101 @@
# app.py
from flask import Flask, render_template, request
import math
# app.py - GIST Assessment Web Application
from flask import Flask, render_template, request, jsonify, send_file
from gist_calculator import GISTCalculator
from questionnaire import QUESTIONNAIRE, COMPONENT_LABELS
import json
from datetime import datetime
import io

app = Flask(__name__)

def calcola_gist_score(scores):
"""Calcola il GIST Score usando la formula completa della tesi."""
pesi = {'fisica': 0.18, 'architetturale': 0.32, 'sicurezza': 0.28, 'conformita': 0.22}
gamma = 0.95

punteggio_finale = sum(pesi[c] * (s ** gamma) for c, s in scores.items())

return round(punteggio_finale, 2)

def determina_livello_maturita(score):
"""Determina il livello di maturità in base al punteggio."""
if score <= 25:
return "Iniziale"
elif score <= 50:
return "In Sviluppo"
elif score <= 75:
return "Avanzato"
else:
return "Ottimizzato"
app.secret_key = 'gist-framework-2025-secure-key'

@app.route('/')
def index():
"""Mostra la pagina iniziale con valori di default."""
def home():
"""Homepage con introduzione al GIST Framework."""
return render_template('index.html')

# La rotta deve essere esattamente "/calcola" e deve accettare il metodo 'POST'
@app.route('/calcola', methods=['POST'])
def calcola():
"""Riceve i dati, calcola e mostra i risultati."""
try:
punteggi = {
'fisica': int(request.form['fisica']),
'architetturale': int(request.form['architetturale']),
'sicurezza': int(request.form['sicurezza']),
'conformita': int(request.form['conformita'])
@app.route('/assessment')
def assessment():
"""
Pagina assessment interattivo con questionario completo.
"""
return render_template(
'assessment.html',
questions=QUESTIONNAIRE,
component_labels=COMPONENT_LABELS
)

@app.route('/api/calculate', methods=['POST'])
def calculate_gist():
"""
API endpoint per calcolo GIST Score.

Request body:
{
"company_name": "Nome Azienda",
"answers": {
"physical": {"power_supply": 60, ...},
"architectural": {...},
"security": {...},
"compliance": {...}
}
}
"""
try:
data = request.json
company_name = data.get('company_name', 'Organizzazione')
answers = data.get('answers', {})

# Validazione base
if not answers:
return jsonify({'error': 'Nessuna risposta fornita'}), 400

# Calcola GIST Score
calculator = GISTCalculator(company_name)
results = calculator.calculate_score(answers)
Comment on lines +49 to +55
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

suggestion: Consider validating the structure of answers before calculation.

Malformed or incomplete answer data could cause errors or incorrect results. Adding validation will help ensure reliable calculations.

Suggested change
# Validazione base
if not answers:
return jsonify({'error': 'Nessuna risposta fornita'}), 400
# Calcola GIST Score
calculator = GISTCalculator(company_name)
results = calculator.calculate_score(answers)
# Validazione base
if not answers:
return jsonify({'error': 'Nessuna risposta fornita'}), 400
def validate_answers_structure(answers):
# Esempio di validazione: answers deve essere un dict con almeno una chiave e valore numerico
if not isinstance(answers, dict):
return False
if not answers:
return False
for key, value in answers.items():
if not isinstance(key, str):
return False
if not isinstance(value, (int, float)):
return False
return True
if not validate_answers_structure(answers):
return jsonify({'error': 'Struttura delle risposte non valida'}), 400
# Calcola GIST Score
calculator = GISTCalculator(company_name)
results = calculator.calculate_score(answers)


score_calcolato = calcola_gist_score(punteggi)
livello = determina_livello_maturita(score_calcolato)
# Aggiungi timestamp
results['timestamp'] = datetime.now().isoformat()

punteggi_per_grafico = list(punteggi.values())

return render_template('index.html',
risultato=score_calcolato,
livello_maturita=livello,
valori_inseriti=punteggi,
dati_grafico=punteggi_per_grafico)
except (ValueError, KeyError):
# Gestisce il caso in cui i dati non siano corretti
return "Errore nei dati inseriti. Assicurati di compilare tutti i campi con numeri.", 400

# Questa parte non è strettamente necessaria per Render, ma è utile per testare in locale
return jsonify(results)

except Exception as e:
return jsonify({'error': str(e)}), 500

@app.route('/results')
def results():
"""
Pagina risultati (riceve dati via query params o POST).
"""
return render_template('results.html')

@app.route('/api/generate-pdf', methods=['POST'])
def generate_pdf():
"""
Genera report PDF dettagliato.
TODO: implementare generazione PDF con reportlab
"""
try:
data = request.json
# Implementeremo questo dopo
return jsonify({'status': 'coming_soon'}), 501

except Exception as e:
return jsonify({'error': str(e)}), 500

@app.route('/about')
def about():
"""Pagina informativa sul framework GIST."""
return render_template('about.html')

@app.errorhandler(404)
def not_found(e):
return render_template('404.html'), 404

@app.errorhandler(500)
def server_error(e):
return render_template('500.html'), 500

if __name__ == '__main__':
app.run(debug=True)
# Development mode
app.run(debug=True, host='0.0.0.0', port=5000)
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

security (python.flask.security.audit.debug-enabled): Detected Flask app with debug=True. Do not deploy to production with this flag enabled as it will leak sensitive information. Instead, consider using Flask configuration variables or setting 'debug' using system environment variables.

Source: opengrep

Loading