docs: documentazione iniziale (requisiti, architettura, roadmap, ADR 0001-0013)

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
This commit is contained in:
davideandClaude Sonnet 5.5 committed 2026-10-11 18:49:10 +02:00
commit a49b1b13ca
24 files changed
+677

No files matched your search

+19
View File
@@ -0,0 +1,19 @@
# NNNN — Titolo
- **Stato**: Proposto | Accettato | Sostituito da NNNN
- **Data**: AAAA-MM-GG
## Contesto
Problema e vincoli.
## Decisione
Cosa si fa.
## Alternative considerate
Opzione → perché sì/no.
## Conseguenze
Positive, negative, cosa va verificato.
## Fonti
Link con data di consultazione.
+28
View File
@@ -0,0 +1,28 @@
# 0001 — Backend: PocketBase
- **Stato**: Accettato (con riserve, vedi R-01)
- **Data**: 2026-10-11
## Contesto
Serve un backend locale, gratuito, con DB, API, storage file e Range. Obiettivo: poca infrastruttura e poco codice.
## Decisione
PocketBase (eseguibile singolo, SQLite embedded, REST, dashboard admin, storage file, hook JS, serve anche `pb_public/`).
## Alternative
- Python + FastAPI + SQLite: più controllo e ffmpeg più naturale, ma più codice da scrivere/mantenere (API, upload, Range, migrazioni).
- Node + Express: idem.
## Conseguenze
- ✔ Un solo binario (~12 MB), nessuna dipendenza, admin UI gratuita per gestire categorie in M1.
- ✔ File serviti con Range: `Serve` usa `http.ServeContent`.
- ✔ Migrazioni in `pb_migrations/` committabili.
- ⚠ **Pre-1.0**: la documentazione ufficiale dice che la retrocompatibilità non è garantita e che non è raccomandato per applicazioni di produzione critiche senza leggere il changelog e applicare migrazioni manuali. Per un uso locale personale è accettabile; **fissare la versione** (oggi v0.40.5) e aggiornare in modo consapevole.
- ⚠ Limite file: i campi file hanno max ~5 MB di default; va alzato nelle opzioni del campo (verificare in M0 anche limiti di body/upload per file grandi).
- ⚠ Il motore JS dei hook (goja) è ES5/ES6 parziale, senza `setTimeout`, né concorrenza dentro un handler: la transcodifica non va eseguita in modo bloccante in un handler → vedi [ADR 0004](0004-pipeline-di-ingest.md).
## Fonti (consultate 2026-10-11)
- https://pocketbase.io/docs/ (versione, avviso pre-1.0, directory)
- https://pocketbase.io/docs/files-handling/ (limite ~5 MB, storage locale/S3)
- https://pocketbase.io/docs/js-overview/ (goja, `$os`, limiti del motore)
- https://github.com/pocketbase/pocketbase/blob/master/tools/filesystem/filesystem.go (`Serve` → `http.ServeContent`)
@@ -0,0 +1,20 @@
# 0002 — Ricodifica video invece di archivio zip/tar.gz
- **Stato**: Accettato
- **Data**: 2026-10-11
## Contesto
Requisito originale: risparmiare spazio salvando i filmati compressi e decomprimendoli all'apertura.
## Decisione
Non usare archivi. Alla prima acquisizione il video viene **ricodificato una volta** con un codec più efficiente e salvato come .mp4 direttamente riproducibile.
## Alternative
- zip/tar.gz con decompressione all'apertura: gli mp4 sono già compressi da codec video, quindi un compressore generico guadagna in genere pochissimo (ordine di 0-2%, **da misurare sui tuoi file in M0**); costa attesa, spazio temporaneo, gestione dei file decompressi aperti e della ricompressione.
- Tenere gli mp4 così come sono: nessun risparmio, nessuna perdita di qualità. Resta un'opzione valida se lo spazio non è un problema.
## Conseguenze
- ✔ Nessun ciclo decomprimi/ricomprimi; seek e ripresa nativi.
- ✔ Risparmio reale (da misurare in M0; l'entità dipende da sorgente e impostazioni).
- ⚠ Ricodificare è **con perdita**: tenere gli originali finché la qualità del risultato non è validata (Q-04).
- ⚠ Costo: tempo di CPU all'ingest.
+40
View File
@@ -0,0 +1,40 @@
# 0003 — Codec di destinazione: AV1 o HEVC (H.265)
- **Stato**: **Proposto** — decide lo spike M0 con i dispositivi di N-07 (Safari iOS, Chrome Android, desktop)
- **Data**: 2026-10-11
## Contesto
Il video è riprodotto dal tag `<video>` del browser, quindi il codec deve essere decodificabile dal browser dell'utente.
## Supporto browser (caniuse, consultato 2026-10-11)
| Browser | AV1 | HEVC |
|---|---|---|
| Chrome / Edge | Supportato | Parziale |
| Firefox | Supportato | Parziale (dalla 137) |
| Safari (macOS/iOS) | Parziale | Supportato |
"Parziale" per HEVC su Chrome/Edge/Firefox dipende da decodifica hardware/OS: va provato sulla macchina reale. Per Safari AV1 è "parziale" (tipicamente richiede hardware recente).
## Browser di destinazione
Requisito dell'utente (2026-10-11, N-07): compatibilità ampia, in particolare Safari iOS, Chrome Android e Windows (su Windows HEVC in Chrome richiede un decoder hardware, quindi non è affidabile). Con questo vincolo un solo codec moderno spesso non basta:
- AV1 su Safari richiede un decoder hardware (Safari 17: Mac M3 e successivi, iPhone 15 Pro, iPhone 16 e successivi): non è garantito sui iPhone più vecchi.
- HEVC su Chrome dipende dall'hardware/OS (decoder hardware su Windows, Linux e ChromeOS; macOS Big Sur 11+ e Android 5.0+).
- H.264 è l'unico indicato come supportato da tutte le versioni di Chrome, Edge, Firefox, Opera e Safari, ma comprime meno.
Fonte: https://developer.mozilla.org/en-US/docs/Web/Media/Guides/Formats/Video_codecs (consultata 2026-10-11; le tabelle HEVC della pagina sono incoerenti: riconfermare con caniuse e con prova diretta in M0).
Strade possibili (la scelta è dell'utente dopo le misure di M0): (a) H.264 come unica copia: massima compatibilità, risparmio di spazio minore; (b) H.264 + una seconda versione AV1/HEVC per i dispositivi che la supportano: più spazio e più complessità; (c) un solo codec moderno e rinuncia ai dispositivi più vecchi. Se si vuole "compatibile con tutti", (a) è la più semplice e va misurata per prima.
## Opzioni
- **AV1** (libsvtav1): libero da royalty, buon supporto su Chrome/Edge/Firefox, ottima efficienza; codifica più lenta.
- **HEVC** (libx265, `-tag:v hvc1`): ottimo su Safari, supporto altrove legato all'hardware; codifica media.
- **H.264 ricodificato con CRF più alto**: massima compatibilità, risparmio minore.
## Decisione provvisoria
Se si usa Chrome/Edge/Firefox → AV1. Se Safari → HEVC. Il default non si fissa finché M0 non ha: (1) verificato la riproduzione sui browser dell'utente, (2) misurato risparmio e tempi su 3 file campione, (3) confrontato la qualità visiva.
Parametri iniziali da tarare (non definitivi): `-c:v libsvtav1 -crf 30 -preset 6` oppure `-c:v libx265 -crf 26 -preset medium -tag:v hvc1`; audio `aac`; sempre `-movflags +faststart`.
## Conseguenze
Se il codec non è supportato, il player mostra un messaggio esplicito (non uno schermo nero).
## Fonti
- https://caniuse.com/av1 · https://caniuse.com/hevc (2026-10-11)
+21
View File
@@ -0,0 +1,21 @@
# 0004 — Pipeline di ingest e transcodifica
- **Stato**: **Proposto** — decide lo spike M0 (R-02)
- **Data**: 2026-10-11
## Contesto
PocketBase non transcodifica. Serve ffmpeg (processo esterno, gratuito). I hook JS possono eseguire comandi (`$os` espone l'esecuzione di comandi di shell), ma il motore non ha concorrenza interna a un handler.
## Opzioni
- **A. Hook su creazione record**: l'upload crea il record `processing`; un hook lancia ffmpeg. Se bloccante, la richiesta HTTP resta appesa per tutta la transcodifica → inadatto. Va verificato se si può avviare il processo in modo non bloccante (`$os.cmd(...).start()`): **non verificato**.
- **B. Script CLI separato** (`scripts/ingest`): lo script ricodifica e poi carica via API. L'upload "passa" dallo script, non dal browser. Semplice e robusto, UX meno immediata.
- **C. Worker che sonda i record `processing`** (script o processo separato) e li lavora in coda, uno alla volta (evita saturare la CPU).
## Decisione provvisoria
Preferire **C** (upload da browser → record `processing` → worker ricodifica → `ready`), con **B** come ripiego. **A** solo se lo spike dimostra che l'esecuzione non bloccante è affidabile.
## Requisiti indipendenti dall'opzione
Idempotenza (rilanciare non duplica); un job alla volta; file temporaneo scritto fuori da `pb_data/` e spostato a fine lavoro; all'avvio i record bloccati in `processing` vengono riconciliati; se l'output è più grande dell'originale si tiene l'originale; scritte statistiche (peso prima/dopo, durata, codec).
## Da verificare in M0
Esecuzione non bloccante da hook; limite di dimensione upload accettato da PocketBase per file grandi; comportamento a riavvio durante la lavorazione.
+19
View File
@@ -0,0 +1,19 @@
# 0005 — Categorie come albero (self-relation)
- **Stato**: Sostituito da 0010
- **Data**: 2026-10-11
## Contesto
Categoria A contiene A1, A2…; oggi serve un livello di sottocategorie, domani potrebbero servirne di più.
## Decisione
Collezione `categories` con campo `parent` (relazione a sé stessa, nullo per le radici). Il modello supporta profondità arbitraria; la UI naviga un livello alla volta in modo generico.
## Alternative
- Due collezioni (categorie, sottocategorie): più rigida, da riscrivere se serve un terzo livello.
- Percorso come testo (`A/A1`): fragile in rinomina/spostamento.
## Conseguenze
- Serve evitare i cicli (validazione in hook di creazione/aggiornamento).
- Eliminazione bloccata se ci sono figli o filmati.
- Un filmato può stare anche in una categoria non foglia (Q-02).
@@ -0,0 +1,16 @@
# 0006 — Salvataggio della posizione di riproduzione
- **Stato**: Sostituito da 0008
- **Data**: 2026-10-11
## Contesto
Alla pausa o chiusura il filmato deve ripartire dal punto in cui era.
## Decisione
Collezione `progress` (un record per filmato) nel DB. Scritture: su `pause`, ogni ~10 s in play, su `visibilitychange`/`pagehide` con `keepalive`.
## Alternative
- `localStorage`: zero backend, ma legato a un solo browser/profilo e perso se si svuotano i dati del sito.
## Conseguenze
Persistente, nel backup di `pb_data/`, e riutilizzabile se in futuro ci saranno più dispositivi. Ultima scrittura vince in caso di due schede aperte.
+16
View File
@@ -0,0 +1,16 @@
# 0007 — Frontend senza build step
- **Stato**: Accettato
- **Data**: 2026-10-11
## Contesto
Interfaccia semplice (alberatura, lista, player, upload). Obiettivo: minima complessità e zero toolchain.
## Decisione
HTML + JavaScript (moduli ES) + CSS serviti da `pb_public/`, SDK JavaScript ufficiale di PocketBase. Player: tag `<video>` nativo.
## Alternative
Svelte/React con Vite: più comodo se la UI cresce, ma aggiunge toolchain e build. Rivalutabile con un nuovo ADR se la UI supera la gestione manuale.
## Conseguenze
Niente transpile né bundle; il codice deve restare organizzato in moduli piccoli.
+24
View File
@@ -0,0 +1,24 @@
# 0008 — Progresso di riproduzione per utente
- **Stato**: Accettato
- **Data**: 2026-10-11
## Contesto
Con gli account (F-12) più persone guardano gli stessi filmati. [ADR 0006](0006-posizione-di-riproduzione.md) prevedeva un record `progress` per filmato, quindi condiviso: la posizione di uno sovrascriverebbe quella degli altri.
## Decisione
Il record `progress` è univoco per coppia (utente, filmato). Resta invariato il resto di ADR 0006 (collezione nel DB, momenti di scrittura: `pause`, ~10 s in play, `visibilitychange`/`pagehide` con `keepalive`). Anche lo stato "visto" (`completed`, F-07) è per utente.
Le API rules permettono a ciascun utente di leggere e scrivere solo i propri record `progress`. Dettaglio dei campi: [02-architettura.md](../02-architettura.md).
## Alternative considerate
- Progresso condiviso (ADR 0006): semplice, ma sbagliato con più utenti.
- `localStorage`: già scartato in ADR 0006; per utente non seguirebbe l'account tra dispositivi.
## Conseguenze
- ✔ Ogni utente riprende dal proprio punto.
- ✔ Eliminando un utente o un filmato i relativi `progress` vanno eliminati a cascata.
- ✘ Più record (utenti × filmati) e una regola in più da testare: un utente non deve poter leggere o scrivere il progresso di un altro (verificare in M4).
- Resta valido: con due schede dello stesso utente sullo stesso filmato vince l'ultima scrittura.
## Fonti
Nessuna esterna: decisione dell'utente del 2026-10-11 ("progresso per utente").
+29
View File
@@ -0,0 +1,29 @@
# 0009 — Accesso: admin = superuser PocketBase, utenti con account
- **Stato**: Sostituito da 0013
- **Data**: 2026-10-11
## Contesto
Requisiti [F-11 e F-12](../01-vision-requisiti.md): per guardare serve un account; solo l'admin (uno solo) aggiunge, modifica ed elimina filmati e categorie. Decisioni dell'utente del 2026-10-11: account creati solo dall'admin, accesso già dall'MVP, admin = superuser.
## Decisione
- **Admin**: l'unico superuser di PocketBase. Non è un ruolo applicativo: l'interfaccia di gestione (upload, categorie, modifica, eliminazione) richiede il login da superuser.
- **Utenti**: record di una collection di autenticazione, creati solo dall'admin; nessuna registrazione libera (`createRule` bloccata).
- **API rules** su `categories` e `videos`: lettura solo con `@request.auth.id != ""`; creazione, modifica, eliminazione bloccate (`null`) ⇒ solo superuser. Su `progress`: ogni utente solo i propri record ([ADR 0008](0008-progresso-per-utente.md)).
- Il server resta su 127.0.0.1 ([02-architettura.md](../02-architettura.md)); l'accesso vale già in locale.
## Alternative considerate
- Ruolo `admin` su un utente normale: permette più admin, ma l'utente ne vuole uno solo; più superficie e più regole da testare.
- Lettura libera senza login: scartata dall'utente (F-12).
- Registrazione libera: scartata, gli account li crea l'admin.
## Conseguenze
- ✔ Nessun codice di ruoli: le rules con `null` sono il meccanismo nativo.
- ✔ Pochissime regole da testare.
- ✘ L'admin non può guardare "come utente" con lo stesso account: i superuser ignorano le rules e non sono utenti della collection; per testare la vista utente serve un account utente.
- ✘ Il frontend deve gestire due login distinti (utente e superuser), da verificare in M1.
- Da verificare in M0/M1: nome e comportamento della collection di autenticazione utenti e del superuser nella versione fissata (la pagina collections non lo specifica); durata del token; reset password creata dall'admin.
## Fonti
- https://pocketbase.io/docs/api-rules-and-filters/ (consultata 2026-10-11): le rules sono ignorate per i superuser; `null` = solo superuser (default); stringa vuota = chiunque; `@request.auth.id != ""` = utente autenticato.
- https://pocketbase.io/docs/collections/ (consultata 2026-10-11): `_superusers` citata solo per la gestione delle collection; esistenza di una collection `users` predefinita e registrazione libera **non** confermate.
@@ -0,0 +1,24 @@
# 0010 — Categorie ad albero con filmati solo nelle foglie
- **Stato**: Accettato
- **Data**: 2026-10-11
- Sostituisce [0005](0005-categorie-ad-albero.md)
## Contesto
Risposta dell'utente a Q-02 (2026-10-11): la struttura è come una serie TV, cioè serie → stagioni → episodi. Gli episodi (filmati) stanno dentro le stagioni, non nella serie.
## Decisione
Resta quanto deciso in ADR 0005: collezione `categories` con `parent` (self-relation, nullo per le radici), profondità arbitraria, UI generica un livello alla volta.
Aggiunta: un filmato può appartenere solo a una categoria **foglia** (senza sottocategorie), e una categoria che contiene filmati non può ricevere sottocategorie. Una categoria è quindi o un contenitore di categorie o un contenitore di filmati, mai entrambe le cose.
## Alternative considerate
- Filmati ovunque nell'albero (ADR 0005): più flessibile, ma una categoria mista (sottocategorie + filmati sciolti) è ambigua da navigare e non corrisponde al modello serie/stagioni.
## Conseguenze
- Serve validazione in hook: creare un filmato in una categoria con figli, creare una sottocategoria sotto una categoria con filmati, e spostare filmati o rami che violerebbero la regola vengono rifiutati con messaggio chiaro.
- Si conferma: no cicli; eliminazione bloccata se ci sono figli o filmati.
- La navigazione ([02-architettura.md](../02-architettura.md)) in una categoria mostra o figli o filmati, mai entrambi.
- Da verificare: l'ordine degli episodi per il "precedente/successivo" (F-08) usa un campo di ordinamento manuale dentro la stagione.
## Fonti
Decisione dell'utente del 2026-10-11 (Q-02).
@@ -0,0 +1,26 @@
# 0011 — Interfaccia admin = dashboard PocketBase; credenziali in `.env`
- **Stato**: Sostituito da 0012
- **Data**: 2026-10-11
## Contesto
L'admin (un solo superuser, [ADR 0009](0009-accesso-admin-e-utenti.md)) deve caricare, modificare ed eliminare filmati e categorie (F-11). Decisioni dell'utente del 2026-10-11: iniziare con la dashboard di PocketBase; la password in `.env`.
## Decisione
- **Interfaccia admin dell'MVP**: la dashboard di PocketBase. Nessuna pagina di gestione nostra; il frontend ([ADR 0007](0007-frontend-vanilla.md)) è solo per gli utenti che guardano. Una pagina di gestione propria è rimandata e, se serve, avrà un nuovo ADR (motivo probabile: stato di ricodifica poco visibile dalla dashboard, vedi F-03).
- **Credenziali**: email e password del superuser stanno in `.env` nella radice, **mai committato** (in `.gitignore`). Il repo contiene solo `.env.example` con nomi e valori fittizi. Lo script di avvio legge `.env` e crea il superuser al primo avvio.
- `.env` serve solo alla creazione iniziale. Dopo, la password vive nel DB di PocketBase: cambiarla da dashboard non aggiorna `.env`, e viceversa. Per evitare ambiguità, `.env` non è la fonte di verità della password dopo il primo avvio.
## Alternative considerate
- Pagina di gestione propria dal giorno uno: più codice e più superficie da proteggere prima di aver validato la pipeline.
- Password solo nell'installer web: nessun file da proteggere, ma non ripetibile in modo scriptato.
## Conseguenze
- ✔ Nessun codice di gestione nell'MVP.
- ✘ Dalla dashboard l'upload è meno guidato e lo stato `processing / ready / error` si vede solo guardando il record.
- ✘ Password in chiaro su disco: accettabile solo perché il server è locale (127.0.0.1); permessi del file ristretti all'utente, mai nei log né nel changelog.
- Da verificare in M0/M1: l'host del file `.env` e come lo script lo legge (nessuna libreria: solo shell); se esiste un comando per aggiornare un superuser già esistente (nella documentazione consultata è confermato solo `superuser create`); dimensione massima di upload dalla dashboard.
## Fonti
- https://pocketbase.io/docs/going-to-production/ (consultata 2026-10-11): il primo superuser si crea con il comando `superuser create EMAIL PASS` o con il link dell'installer web scritto nei log. Nessun meccanismo generale per i segreti: le impostazioni sono salvate in chiaro nel DB; l'unica variabile d'ambiente citata serve a cifrarle (`--encryptionEnv`).
- https://pocketbase.io/docs/use-as-framework/ (consultata 2026-10-11): non descrive la creazione di superuser da CLI né credenziali via variabili d'ambiente. Quindi PocketBase **non** legge la password da `.env` da solo: lo fa lo script di avvio.
+28
View File
@@ -0,0 +1,28 @@
# 0012 — Pannello admin proprio; superuser creato come da documentazione PocketBase
- **Stato**: Accettato
- **Data**: 2026-10-11
- Sostituisce [0011](0011-interfaccia-admin-e-credenziali.md)
## Contesto
Nuova decisione dell'utente (2026-10-11): niente `.env` per la password; seguire la documentazione di PocketBase; l'admin gestisce tutto da un pannello (dashboard) intuitivo creato da noi, non dalla dashboard standard di PocketBase.
## Decisione
- **Superuser**: creato come indica la documentazione ufficiale: link dell'installer web scritto nei log al primo avvio, oppure `superuser create EMAIL PASS` da terminale. Nessun `.env` con la password, nessuno script che la legge. La password vive solo nel DB di PocketBase.
- **Pannello admin**: pagina del frontend ([ADR 0007](0007-frontend-vanilla.md), `pb_public/`, senza build step) accessibile solo dopo il login da superuser (`pb.collection('_superusers').authWithPassword`). Requisito: [F-14](../01-vision-requisiti.md).
- Le operazioni di scrittura restano protette dalle API rules ([ADR 0009](0009-accesso-admin-e-utenti.md)): il pannello è solo un'interfaccia; nascondere i pulsanti non è sicurezza.
- La dashboard standard di PocketBase resta disponibile come strumento di emergenza dell'admin (schema, ripristino), non come interfaccia d'uso.
## Alternative considerate
- Solo dashboard PocketBase (ADR 0011): zero codice, ma poco intuitiva per caricare e vedere lo stato della ricodifica.
- Password in `.env`: scartata dall'utente; PocketBase non la legge comunque da solo.
## Conseguenze
- ✔ Interfaccia pensata per le operazioni reali: carica, stato, categorie.
- ✘ Più codice frontend da scrivere e testare (fase M3b in [03-roadmap.md](../03-roadmap.md)), incluso il login da superuser separato da quello utenti.
- Casi limite da coprire: token scaduto durante un upload lungo (la durata del token superuser non è specificata nella documentazione consultata: verificare in M0), upload interrotto, eliminazione con contenuti (bloccata), doppio invio, rifiuto della regola foglie ([ADR 0010](0010-filmati-solo-nelle-foglie.md)) con messaggio chiaro.
- Accessibilità di base: tastiera, etichette dei campi, messaggi d'errore in italiano.
## Fonti
- https://pocketbase.io/docs/authentication/ (consultata 2026-10-11): il superuser si autentica con `authWithPassword` sulla collection `_superusers`; le rules sono ignorate per i superuser; durata del token non indicata.
- https://pocketbase.io/docs/going-to-production/ (consultata 2026-10-11): primo superuser via `superuser create EMAIL PASS` o installer web (link nei log).
+24
View File
@@ -0,0 +1,24 @@
# 0013 — Accesso: admin = superuser, utenti con account, server sulla rete di casa
- **Stato**: Accettato
- **Data**: 2026-10-11
- Sostituisce [0009](0009-accesso-admin-e-utenti.md)
## Contesto
L'app gira su un Raspberry Pi e telefoni, tablet e PC la raggiungono dall'indirizzo IP nella rete di casa (decisione dell'utente, 2026-10-11, N-01). L'ADR 0009 prevedeva il server solo su 127.0.0.1.
## Decisione
Resta quanto deciso in ADR 0009: admin = unico superuser PocketBase; utenti con account creati solo dall'admin, solo lettura; API rules: lettura con `@request.auth.id != ""`, scrittura (`null`) solo al superuser; `progress` solo propri record ([ADR 0008](0008-progresso-per-utente.md)); accesso già dall'MVP.
Cambia: il server ascolta sull'interfaccia di rete locale del Raspberry, non solo su 127.0.0.1. Nessuna esposizione a Internet (niente port forwarding sul router). Il trasporto (HTTP o HTTPS) è aperto: Q-16.
## Alternative considerate
- Solo 127.0.0.1 (ADR 0009): incompatibile con telefoni e tablet.
- Esposizione a Internet: fuori scopo per ora (fase M6).
## Conseguenze
- ✔ Le rules restrittive diventano indispensabili da subito: chiunque sia sulla rete di casa raggiunge il server.
- ✘ Su HTTP le password viaggiano in chiaro sul Wi-Fi di casa (R-08, Q-16).
- Da verificare in M0: indirizzo di ascolto e configurazione di PocketBase su rete locale (documentazione ufficiale); IP del Raspberry fisso o nome locale.
## Fonti
Decisione dell'utente del 2026-10-11. Fatti su PocketBase come in ADR 0009 (https://pocketbase.io/docs/api-rules-and-filters/ e https://pocketbase.io/docs/authentication/, consultate 2026-10-11).