add initial template
This commit is contained in:
parent
4ed1e88dc2
commit
45a93e5a23
13 changed files with 457 additions and 13 deletions
58
.gitignore
vendored
58
.gitignore
vendored
|
@ -1,2 +1,56 @@
|
||||||
.idea
|
# Virtual environment
|
||||||
backend/.env
|
venv/
|
||||||
|
env/
|
||||||
|
.venv/
|
||||||
|
|
||||||
|
# Python
|
||||||
|
__pycache__/
|
||||||
|
*.py[cod]
|
||||||
|
*$py.class
|
||||||
|
*.so
|
||||||
|
.Python
|
||||||
|
build/
|
||||||
|
develop-eggs/
|
||||||
|
dist/
|
||||||
|
downloads/
|
||||||
|
eggs/
|
||||||
|
.eggs/
|
||||||
|
lib/
|
||||||
|
lib64/
|
||||||
|
parts/
|
||||||
|
sdist/
|
||||||
|
var/
|
||||||
|
wheels/
|
||||||
|
*.egg-info/
|
||||||
|
.installed.cfg
|
||||||
|
*.egg
|
||||||
|
|
||||||
|
# IDE
|
||||||
|
.vscode/
|
||||||
|
.idea/
|
||||||
|
*.swp
|
||||||
|
*.swo
|
||||||
|
*~
|
||||||
|
|
||||||
|
# OS
|
||||||
|
.DS_Store
|
||||||
|
.DS_Store?
|
||||||
|
._*
|
||||||
|
.Spotlight-V100
|
||||||
|
.Trashes
|
||||||
|
ehthumbs.db
|
||||||
|
Thumbs.db
|
||||||
|
|
||||||
|
# Logs
|
||||||
|
*.log
|
||||||
|
|
||||||
|
# Environment variables
|
||||||
|
.env
|
||||||
|
.env.local
|
||||||
|
.env.*.local
|
||||||
|
|
||||||
|
# Node modules (se installi http-server globalmente)
|
||||||
|
node_modules/
|
||||||
|
|
||||||
|
# Docker
|
||||||
|
.dockerignore
|
18
README.md
18
README.md
|
@ -1,2 +1,18 @@
|
||||||
# Team NPT
|
# Template per Hackathon
|
||||||
|
|
||||||
|
## 🚀 Avvio Rapido
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# Avvia tutto con un comando
|
||||||
|
./start.sh
|
||||||
|
|
||||||
|
#Comandi utili per vedere dati db su mongosh
|
||||||
|
mongosh
|
||||||
|
show dbs
|
||||||
|
use simple_db
|
||||||
|
show collections
|
||||||
|
db.items.find()
|
||||||
|
```
|
||||||
|
|
||||||
|
Il frontend sarà disponibile su http://localhost:3000
|
||||||
|
Il backend sarà hostato localmente su http://localhost:8000
|
97
app/index.html
Normal file
97
app/index.html
Normal file
|
@ -0,0 +1,97 @@
|
||||||
|
<!DOCTYPE html>
|
||||||
|
<html lang="it">
|
||||||
|
<head>
|
||||||
|
<meta charset="UTF-8">
|
||||||
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||||
|
<title>Template APP</title>
|
||||||
|
<style>
|
||||||
|
body {
|
||||||
|
font-family: Arial, sans-serif;
|
||||||
|
max-width: 800px;
|
||||||
|
margin: 50px auto;
|
||||||
|
padding: 20px;
|
||||||
|
background-color: #f5f5f5;
|
||||||
|
}
|
||||||
|
.container {
|
||||||
|
background: white;
|
||||||
|
padding: 30px;
|
||||||
|
border-radius: 10px;
|
||||||
|
box-shadow: 0 2px 10px rgba(0,0,0,0.1);
|
||||||
|
}
|
||||||
|
h1 {
|
||||||
|
color: #333;
|
||||||
|
text-align: center;
|
||||||
|
margin-bottom: 30px;
|
||||||
|
}
|
||||||
|
.button-group {
|
||||||
|
display: flex;
|
||||||
|
gap: 20px;
|
||||||
|
justify-content: center;
|
||||||
|
margin-bottom: 30px;
|
||||||
|
}
|
||||||
|
button {
|
||||||
|
padding: 15px 30px;
|
||||||
|
font-size: 16px;
|
||||||
|
border: none;
|
||||||
|
border-radius: 5px;
|
||||||
|
cursor: pointer;
|
||||||
|
transition: background-color 0.3s;
|
||||||
|
}
|
||||||
|
.btn-get {
|
||||||
|
background-color: #4CAF50;
|
||||||
|
color: white;
|
||||||
|
}
|
||||||
|
.btn-get:hover {
|
||||||
|
background-color: #45a049;
|
||||||
|
}
|
||||||
|
.btn-post {
|
||||||
|
background-color: #2196F3;
|
||||||
|
color: white;
|
||||||
|
}
|
||||||
|
.btn-post:hover {
|
||||||
|
background-color: #1976D2;
|
||||||
|
}
|
||||||
|
.result {
|
||||||
|
background-color: #f9f9f9;
|
||||||
|
border: 1px solid #ddd;
|
||||||
|
border-radius: 5px;
|
||||||
|
padding: 20px;
|
||||||
|
margin-top: 20px;
|
||||||
|
white-space: pre-wrap;
|
||||||
|
font-family: monospace;
|
||||||
|
max-height: 400px;
|
||||||
|
overflow-y: auto;
|
||||||
|
}
|
||||||
|
.status {
|
||||||
|
padding: 10px;
|
||||||
|
border-radius: 5px;
|
||||||
|
margin-bottom: 10px;
|
||||||
|
}
|
||||||
|
.success {
|
||||||
|
background-color: #d4edda;
|
||||||
|
color: #155724;
|
||||||
|
border: 1px solid #c3e6cb;
|
||||||
|
}
|
||||||
|
.error {
|
||||||
|
background-color: #f8d7da;
|
||||||
|
color: #721c24;
|
||||||
|
border: 1px solid #f5c6cb;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<div class="container">
|
||||||
|
<h1>🚀 Simple Fullstack App</h1>
|
||||||
|
|
||||||
|
<div class="button-group">
|
||||||
|
<button class="btn-get" onclick="getData()">📥 GET Data</button>
|
||||||
|
<button class="btn-post" onclick="createData()">📤 POST Data</button>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div id="status"></div>
|
||||||
|
<div id="result" class="result" style="display: none;"></div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<script src="script.js"></script>
|
||||||
|
</body>
|
||||||
|
</html>
|
76
app/script.js
Normal file
76
app/script.js
Normal file
|
@ -0,0 +1,76 @@
|
||||||
|
const API_BASE_URL = 'http://localhost:8000';
|
||||||
|
|
||||||
|
// Funzione per mostrare messaggi di status
|
||||||
|
function showStatus(message, isSuccess = true) {
|
||||||
|
const statusDiv = document.getElementById('status');
|
||||||
|
statusDiv.innerHTML = `<div class="status ${isSuccess ? 'success' : 'error'}">${message}</div>`;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Funzione per mostrare i risultati
|
||||||
|
function showResult(data) {
|
||||||
|
const resultDiv = document.getElementById('result');
|
||||||
|
resultDiv.style.display = 'block';
|
||||||
|
resultDiv.textContent = JSON.stringify(data, null, 2);
|
||||||
|
}
|
||||||
|
|
||||||
|
// GET: Ottiene dati dal database
|
||||||
|
async function getData() {
|
||||||
|
try {
|
||||||
|
console.log('📥 Richiesta GET in corso...');
|
||||||
|
showStatus('📥 Richiesta GET in corso...', true);
|
||||||
|
|
||||||
|
const response = await fetch(`${API_BASE_URL}/api/data`);
|
||||||
|
const data = await response.json();
|
||||||
|
|
||||||
|
if (response.ok) {
|
||||||
|
showStatus('✅ Dati ottenuti con successo!', true);
|
||||||
|
showResult(data);
|
||||||
|
} else {
|
||||||
|
showStatus(`❌ Errore: ${data.detail || 'Errore sconosciuto'}`, false);
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
console.error('Errore GET:', error);
|
||||||
|
showStatus(`❌ Errore di connessione: ${error.message}`, false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// POST: Inserisce dati nel database
|
||||||
|
async function createData() {
|
||||||
|
try {
|
||||||
|
console.log('📤 Richiesta POST in corso...');
|
||||||
|
showStatus('📤 Richiesta POST in corso...', true);
|
||||||
|
|
||||||
|
const response = await fetch(`${API_BASE_URL}/api/data`, {
|
||||||
|
method: 'POST',
|
||||||
|
headers: {
|
||||||
|
'Content-Type': 'application/json',
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
const data = await response.json();
|
||||||
|
|
||||||
|
if (response.ok) {
|
||||||
|
showStatus('✅ Dato inserito con successo!', true);
|
||||||
|
showResult(data);
|
||||||
|
} else {
|
||||||
|
showStatus(`❌ Errore: ${data.detail || 'Errore sconosciuto'}`, false);
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
console.error('Errore POST:', error);
|
||||||
|
showStatus(`❌ Errore di connessione: ${error.message}`, false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Test di connessione all'avvio
|
||||||
|
window.addEventListener('load', async () => {
|
||||||
|
try {
|
||||||
|
const response = await fetch(`${API_BASE_URL}/`);
|
||||||
|
if (response.ok) {
|
||||||
|
console.log('✅ Backend connesso!');
|
||||||
|
} else {
|
||||||
|
console.log('❌ Backend non raggiungibile');
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
console.log('❌ Backend non raggiungibile:', error.message);
|
||||||
|
}
|
||||||
|
});
|
|
@ -1,3 +0,0 @@
|
||||||
# ENV
|
|
||||||
- MONGO_INITDB_ROOT_USERNAME=
|
|
||||||
- MONGO_INITDB_ROOT_PASSWORD=
|
|
|
@ -1,15 +1,30 @@
|
||||||
|
version: '3.8'
|
||||||
|
|
||||||
services:
|
services:
|
||||||
mongodb:
|
mongodb:
|
||||||
image: mongo:8.0.0
|
image: mongo:7.0
|
||||||
container_name: mongodb
|
container_name: simple_mongodb
|
||||||
restart: unless-stopped
|
|
||||||
ports:
|
ports:
|
||||||
- "27017:27017"
|
- "27017:27017"
|
||||||
environment:
|
environment:
|
||||||
- MONGO_INITDB_ROOT_USERNAME=${MONGO_INITDB_ROOT_USERNAME}
|
MONGO_INITDB_ROOT_USERNAME: admin
|
||||||
- MONGO_INITDB_ROOT_PASSWORD=${MONGO_INITDB_ROOT_PASSWORD}
|
MONGO_INITDB_ROOT_PASSWORD: password
|
||||||
volumes:
|
volumes:
|
||||||
- mongo-data:/data/db
|
- mongodb_data:/data/db
|
||||||
|
restart: unless-stopped
|
||||||
|
|
||||||
|
mongo-express:
|
||||||
|
image: mongo-express:latest
|
||||||
|
container_name: mongo_express
|
||||||
|
ports:
|
||||||
|
- "8081:8081"
|
||||||
|
environment:
|
||||||
|
ME_CONFIG_MONGODB_ADMINUSERNAME: admin
|
||||||
|
ME_CONFIG_MONGODB_ADMINPASSWORD: password
|
||||||
|
ME_CONFIG_MONGODB_URL: mongodb://admin:password@mongodb:27017/
|
||||||
|
depends_on:
|
||||||
|
- mongodb
|
||||||
|
restart: unless-stopped
|
||||||
|
|
||||||
volumes:
|
volumes:
|
||||||
mongo-data:
|
mongodb_data:
|
||||||
|
|
22
backend/main.py
Normal file
22
backend/main.py
Normal file
|
@ -0,0 +1,22 @@
|
||||||
|
from fastapi import FastAPI
|
||||||
|
from fastapi.middleware.cors import CORSMiddleware
|
||||||
|
from routes import router
|
||||||
|
|
||||||
|
app = FastAPI(title="Simple Fullstack API")
|
||||||
|
|
||||||
|
# CORS per permettere richieste dal frontend
|
||||||
|
app.add_middleware(
|
||||||
|
CORSMiddleware,
|
||||||
|
allow_origins=["*"],
|
||||||
|
allow_credentials=True,
|
||||||
|
allow_methods=["*"],
|
||||||
|
allow_headers=["*"],
|
||||||
|
)
|
||||||
|
|
||||||
|
# Includi le route
|
||||||
|
app.include_router(router)
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
import uvicorn
|
||||||
|
print("🚀 Avvio server FastAPI...")
|
||||||
|
uvicorn.run(app, host="0.0.0.0", port=8000)
|
|
@ -0,0 +1,4 @@
|
||||||
|
fastapi==0.104.1
|
||||||
|
uvicorn[standard]==0.24.0
|
||||||
|
pymongo==4.6.0
|
||||||
|
python-multipart==0.0.6
|
50
backend/routes.py
Normal file
50
backend/routes.py
Normal file
|
@ -0,0 +1,50 @@
|
||||||
|
from fastapi import APIRouter, HTTPException
|
||||||
|
from pymongo import MongoClient
|
||||||
|
from datetime import datetime
|
||||||
|
|
||||||
|
# Router per le API
|
||||||
|
router = APIRouter()
|
||||||
|
|
||||||
|
# Connessione MongoDB
|
||||||
|
client = MongoClient("mongodb://localhost:27017/")
|
||||||
|
db = client["simple_db"]
|
||||||
|
collection = db["items"]
|
||||||
|
|
||||||
|
@router.get("/")
|
||||||
|
def read_root():
|
||||||
|
"""Root endpoint per test connessione"""
|
||||||
|
return {"message": "Simple Fullstack API is running!"}
|
||||||
|
|
||||||
|
@router.get("/api/data")
|
||||||
|
def get_data():
|
||||||
|
"""GET: Ottiene il primo documento dal database"""
|
||||||
|
try:
|
||||||
|
# Trova il primo documento disponibile
|
||||||
|
document = collection.find_one()
|
||||||
|
if document:
|
||||||
|
# Converti ObjectId in stringa per JSON serialization
|
||||||
|
document["_id"] = str(document["_id"])
|
||||||
|
return {"success": True, "data": document}
|
||||||
|
else:
|
||||||
|
return {"success": False, "message": "Nessun dato trovato nel database"}
|
||||||
|
except Exception as e:
|
||||||
|
raise HTTPException(status_code=500, detail=f"Errore database: {str(e)}")
|
||||||
|
|
||||||
|
@router.post("/api/data")
|
||||||
|
def create_data():
|
||||||
|
"""POST: Inserisce un dato hardcoded nel database"""
|
||||||
|
try:
|
||||||
|
# Dato hardcoded da inserire
|
||||||
|
new_item = {
|
||||||
|
"name": "Item di esempio",
|
||||||
|
"description": "Questo è un item creato tramite API",
|
||||||
|
"timestamp": datetime.now().isoformat(),
|
||||||
|
"value": 42
|
||||||
|
}
|
||||||
|
|
||||||
|
result = collection.insert_one(new_item)
|
||||||
|
new_item["_id"] = str(result.inserted_id)
|
||||||
|
|
||||||
|
return {"success": True, "message": "Dato inserito con successo", "data": new_item}
|
||||||
|
except Exception as e:
|
||||||
|
raise HTTPException(status_code=500, detail=f"Errore inserimento: {str(e)}")
|
113
start.sh
Executable file
113
start.sh
Executable file
|
@ -0,0 +1,113 @@
|
||||||
|
#!/bin/bash
|
||||||
|
|
||||||
|
echo "🚀 Avvio Simple Fullstack App..."
|
||||||
|
|
||||||
|
# Colori per output
|
||||||
|
GREEN='\033[0;32m'
|
||||||
|
BLUE='\033[0;34m'
|
||||||
|
YELLOW='\033[1;33m'
|
||||||
|
NC='\033[0m' # No Color
|
||||||
|
|
||||||
|
# Funzione per stampare messaggi colorati
|
||||||
|
print_status() {
|
||||||
|
echo -e "${BLUE}[INFO]${NC} $1"
|
||||||
|
}
|
||||||
|
|
||||||
|
print_success() {
|
||||||
|
echo -e "${GREEN}[SUCCESS]${NC} $1"
|
||||||
|
}
|
||||||
|
|
||||||
|
print_warning() {
|
||||||
|
echo -e "${YELLOW}[WARNING]${NC} $1"
|
||||||
|
}
|
||||||
|
|
||||||
|
# Controlla se Python3 è installato
|
||||||
|
if ! command -v python3 &> /dev/null; then
|
||||||
|
echo "❌ Python3 non trovato. Installa Python3 prima di continuare."
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Controlla se Docker è installato
|
||||||
|
if ! command -v docker &> /dev/null; then
|
||||||
|
echo "❌ Docker non trovato. Installa Docker prima di continuare."
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Controlla se http-server è installato
|
||||||
|
if ! command -v http-server &> /dev/null; then
|
||||||
|
print_warning "http-server non trovato. Installando..."
|
||||||
|
npm install -g http-server
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Crea virtual environment se non esiste
|
||||||
|
if [ ! -d "venv" ]; then
|
||||||
|
print_status "Creazione virtual environment..."
|
||||||
|
python3 -m venv venv
|
||||||
|
print_success "Virtual environment creato!"
|
||||||
|
else
|
||||||
|
print_status "Virtual environment già esistente"
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Attiva virtual environment
|
||||||
|
print_status "Attivazione virtual environment..."
|
||||||
|
source venv/bin/activate
|
||||||
|
|
||||||
|
# Installa dipendenze
|
||||||
|
print_status "Installazione dipendenze Python..."
|
||||||
|
pip install -r backend/requirements.txt
|
||||||
|
print_success "Dipendenze installate!"
|
||||||
|
|
||||||
|
# Avvia MongoDB con Docker
|
||||||
|
print_status "Avvio MongoDB con Docker..."
|
||||||
|
cd backend
|
||||||
|
docker-compose up -d
|
||||||
|
cd ..
|
||||||
|
|
||||||
|
# Aspetta che MongoDB sia pronto
|
||||||
|
print_status "Attesa MongoDB..."
|
||||||
|
sleep 5
|
||||||
|
|
||||||
|
# Avvia backend in background
|
||||||
|
print_status "Avvio backend FastAPI..."
|
||||||
|
cd backend
|
||||||
|
python main.py &
|
||||||
|
BACKEND_PID=$!
|
||||||
|
cd ..
|
||||||
|
|
||||||
|
# Aspetta che il backend sia pronto
|
||||||
|
print_status "Attesa backend..."
|
||||||
|
sleep 3
|
||||||
|
|
||||||
|
# Avvia frontend
|
||||||
|
print_status "Avvio frontend..."
|
||||||
|
cd app
|
||||||
|
http-server -p 3000 -o &
|
||||||
|
FRONTEND_PID=$!
|
||||||
|
cd ..
|
||||||
|
|
||||||
|
print_success "🎉 Tutto avviato!"
|
||||||
|
echo ""
|
||||||
|
echo "📱 Frontend: http://localhost:3000"
|
||||||
|
echo "🔧 Backend API: http://localhost:8000"
|
||||||
|
echo "🗄️ MongoDB: localhost:27017"
|
||||||
|
echo ""
|
||||||
|
echo "💡 Premi Ctrl+C per fermare tutto"
|
||||||
|
|
||||||
|
# Funzione per cleanup
|
||||||
|
cleanup() {
|
||||||
|
echo ""
|
||||||
|
print_status "Fermando servizi..."
|
||||||
|
kill $BACKEND_PID 2>/dev/null
|
||||||
|
kill $FRONTEND_PID 2>/dev/null
|
||||||
|
cd backend
|
||||||
|
docker-compose down
|
||||||
|
cd ..
|
||||||
|
print_success "Servizi fermati!"
|
||||||
|
exit 0
|
||||||
|
}
|
||||||
|
|
||||||
|
# Intercetta Ctrl+C
|
||||||
|
trap cleanup SIGINT
|
||||||
|
|
||||||
|
# Mantieni lo script in esecuzione
|
||||||
|
wait
|
Loading…
Add table
Add a link
Reference in a new issue