7.1 KiB
7.1 KiB
Analisi del Progetto Bookish
1. Qualità del Codice
Punti di Forza
- Architettura modulare: blueprint Flask separati per convertitore, reader, API
- Servizi isolati: converter, formatter, SSE manager, database come moduli indipendenti
- Pattern Factory:
create_app()con registrazione blueprint e init DB - Responsabilità chiare: ogni file ha uno scopo ben definito
- Thread safety: lock
threading.Lock()in SSE manager per accesso concorrente - Frontend vanilla: nessuna dipendenza framework pesante, codice lineare
- Path robust:
os.path.basename(),secure_filename(), sanity check su ogni path - Error handling: try/except in routes con fallback e messaggi d'errore
Aree di Miglioramento
- Tipo: usare mypy con typing anche per i parametri Flask
- Test: nessuna suite di test (accettabile per single-user)
- Logging: log minimale, potrebbe essere più strutturato
- Cleanup SSE: il thread cleanup ogni 60s funziona ma non è elegante
- Race condition DB:
allow_commitcome flag per SKIP/LOCKED è un workaround. In pratica SQLite gestisce bene le race con WAL mode — testato con debounce 1.5s e non dà problemi
2. Sicurezza
- ✅ Path traversal:
secure_filename()+os.path.basename()+ sanity check - ✅ Estensione validata: controllo su SUPPORTED_FORMATS/OUTPUT_FORMATS_BY_INPUT
- ✅ MIME check: al download per prevenire tipo sbagliato
- ✅ Cleanup automatico: file temporanei eliminati dopo 1h
- ✅ SQLite parametriziato: query con placeholder
?, niente interpolazione stringhe - ✅ Niente eval/exec: zero codice dinamico pericoloso
- ✅ CSRF: non rilevante per single-user con API REST semplici
- ⚠️ Secret key hardcoded: default in
app.py. ImpostareBOOKISH_SECRETin produzione - ⚠️ Upload estensione: solo check estensione, non MIME reale (sufficiente per single-user)
- ⚠️ No rate limiting: Upload illimitati (accettabile per uso personale)
3. Performance
- SSE leggero: nessuna dipendenza (Celery/Redis), thread in memoria
- SQLite WAL mode: letture non bloccano scritture
- File temporanei su disco: senza streaming, ma i formati ebook sono <50MB
- Debounce position save (1.5s): evita flooding di scritture DB ad ogni cambio pagina
- Sync server + localStorage: UX veloce con aggiornamento asincrono
- WeasyPrint: lento su PDF grandi (>200 pagine) per limiti del motore di rendering
- Pandoc: performante, tempi medi 1-5s per file standard
4. Manutenibilità
- Codice auto-documentante: nomi di funzioni e variabili chiari
- Config centralizzata:
config.pycon tutti i path e formati - Servizi disaccoppiati: modificare il converter non impatta reader o API
- Separazione API: le rotte
/api/sono in blueprint dedicato - reader.js separato: anche se lungo (800+ righe), è l'unico file JS del reader
- CSS strutturato: sezioni per reader, converter, generiche
- Documentazione completa: README, architecture, deploy, wiki
5. Affidabilità
- Porta libera automatica: se 5000 occupata,
find_free_port()scorre fino a trovare una libera - Cleanup temp: thread timer ogni 60 minuti elimina file scaduti
- Fallback localStorage: se server API non risponde, bookmarks e posizioni funzionano comunque (solo in locale)
- Content hash come ID: stesso file → stesso hash → stessi segnalibri, anche su PC diverso
- Auto-creazione DB: database creato al primo avvio senza intervento manuale
- Gestione errori conversione: errori Pandoc catturati e propagati come messaggio utente
6. Dipendenze
Python (produzione)
| Pacchetto | Versione | Ruolo |
|---|---|---|
| Flask | ≥3.0 | Web framework |
| Flask-CORS | ≥4.0 | CORS per API |
| pypandoc_binary | ≥2.0 | Pandoc binary + binding |
| WeasyPrint | ≥62 | PDF da HTML |
| python-docx | ≥1.0 | DOCX post-processing |
| beautifulsoup4 | ≥4.0 | HTML/tabelle post-processing |
| lxml | ≥5.0 | Parser XML per BeautifulSoup |
| Werkzeug | ≥3.0 | Secure filename, HTTP utilities |
| markdown | ≥3.0 | MD → HTML per anteprime |
| pdfminer.six | ≥2022 | Testo base da PDF |
Frontend (browser)
| Libreria | Versione | Ruolo |
|---|---|---|
| epub.js | 0.3.93 | Render EPUB |
| pdf.js | 3.x | Render PDF |
| PDF.js | 3.x | Text layer PDF |
| jszip | 3.x | ZIP per EPUB |
7. Architettura Componenti
┌──────────────────────────────────────────────────┐
│ Flask App │
│ │
│ ┌──────────┐ ┌──────────┐ ┌──────────┐ │
│ │ Convert │ │ Reader │ │ API │ │
│ │ /upload │ │ /reader │ │ /api/* │ │
│ │ /progress│ │ /reader/ │ │ │ │
│ │ /download│ │ <file> │ │ bookmarks│ │
│ └─────┬────┘ └────┬─────┘ └────┬─────┘ │
│ │ │ │ │
│ ┌─────▼─────────────▼─────────────▼──────┐ │
│ │ Services │ │
│ │ ┌──────────┐ ┌──────────┐ │ │
│ │ │converter │ │ database │─▶ SQLite │ │
│ │ │sse_mgr │ └──────────┘ │ │
│ │ │formatter │ │ │
│ │ └──────────┘ │ │
│ └──────────────────────────────────────────┘ │
│ │
│ Filesystem: uploads/ converted/ bookish.db │
└──────────────────────────────────────────────────┘
8. Conclusioni
Bookish è un'applicazione solida per il suo scopo: self-hosted, single-user, conversione e lettura ebook.
Cosa funziona bene
- Il flusso conversione con SSE progress è semplice ma efficace
- Il reader supporta EPUB, PDF e formati testo in un'unica interfaccia
- La persistenza segnalibri con content_hash è robusta: funziona anche su PC diversi
- Il fallback localStorage assicura che il reader non si rompa se il server API è giù
- Slider larghezza e help modal completano l'UX del reader
- La documentazione è completa e in italiano
Cosa sarebbe migliorabile (ma non necessario per single-user)
- Suite di test automatici
- Pipeline CI/CD
- HTTPS nativo (gestito da reverse proxy in produzione)
- Gestione code block più sofisticata nel reader testo
- Mobile optimization
- Logging strutturato (può essere aggiunto con poche righe)