Home

Changelog

Storico delle modifiche rilasciate. Il formato segue «Keep a Changelog».

  1. v0.12.0 11 settembre 2026 Ultima versione

    Aggiunto

    • **La registrazione è di gruppo: fino a sei adulti, ciascuno con la sua email** (RF-FORM-035…040). Sotto il campo Professione del form pubblico c'è «Aggiungi un adulto», nella forma già in uso per i minori: una riga con Nome, Cognome, **Email obbligatoria** e Professione, fino a cinque oltre al referente. Due differenze deliberate dal blocco minori — **nessuna casella da spuntare prima**, perché aggiungere la riga *è* la dichiarazione, e al tetto il pulsante **sparisce** invece di restare disabilitato, sostituito dalla nota che dice perché. Le righe sono numerate **a partire da 2**: chi compila è l'adulto 1, e la numerazione dice quante persone ci sono in tutto. L'email di ogni riga è univoca **anche dentro la stessa registrazione**, dove due righe con lo stesso indirizzo sono la stessa persona due volte, e l'errore si accende **sulla riga** di quell'indirizzo — il vincolo d'unicità dice *che* c'è un duplicato, non *di chi*, quindi il modulo tiene traccia di quale INSERT è in volo quando l'indice scatta. Il tetto vive in configurazione (registration.maxAdultsPerRegistration, default 6): è una scelta **provvisoria del team** per poter costruire, non la risposta del cliente (B23), e quando arriverà cambierà un valore, non il codice.
    • **Un clic di conferma, un biglietto a testa.** La verifica reale dell'indirizzo resta **una sola**, quella del referente — «farla su tutte è troppo» — ma il biglietto va **alla persona**: il referente clicca e nella stessa transazione tutto il gruppo passa a confermato con un QR ciascuno, poi ogni adulto riceve la **propria Email 3**, al proprio indirizzo, col proprio biglietto e il proprio link di rinuncia. Per dargli un link personale senza dargli un secondo clic di conferma, alla conferma si emette per ciascuno un token **già speso** (usedAt valorizzato): non conferma nulla — la conferma è avvenuta — ma apre biglietto e rinuncia. Il PDF unico resta quello della **famiglia**: il referente e i suoi minori.
    • **Le gallerie hanno posti veri, estratti dalla pianta** (RF-BO-053). Il dato non esisteva: della platea c'era un foglio digitalizzato, delle gallerie solo una capienza dichiarata. La fonte è la pianta del Brancaccio, dove si chiamano **I e II balconata** — un PDF vettoriale, quindi ogni numero di posto è un'etichetta con la sua posizione e la geometria si ricostruisce dalle coordinate. Lo script riconosce **ed elimina le etichette di fila** che il disegno stampa in mezzo alle poltrone (si smascherano perché rompono il passo della numerazione: …27, **5**, 25), separa i settori dai vuoti orizzontali — che sono i corridoi — e scrive un JSON committato e revisionabile con un rapporto delle anomalie. Risultato: **G1 399 posti su 14 file, G2 321 su 10**, contro i 400 e 300 dichiarati e mai confermati dal teatro. La **capienza diventa una conseguenza del layout** — tanti posti quanti ne disegna la pianta — invece di un numero tenuto a parte, che infatti dal disegno divergeva.
    • **La pianta delle gallerie è la stessa della platea.** Non una mappa nuova: quella della platea, resa capace di disegnare un'altra area. Stessa griglia, stessa legenda, stesso zoom, stessi due gesti — clic su un posto libero per assegnare, «Sposta» dal posto occupato per spostare. Un primo tentativo aveva prodotto un componente dedicato (GalleryMap): è stato **buttato** quando è emerso che serviva la stessa interazione, perché due mappe che si comportano diversamente sono due cose da imparare invece di una. Il componente condiviso prende tre parametri e nient'altro: l'**area**, l'**azione** a cui inviare — in galleria una sola, assignGallerySeat, che assegna e sposta col medesimo gesto e viaggia con l'**id** del posto perché il numero da solo non ne identifica uno — e i corridoi trasversali, che sono della platea. Le due gallerie stanno una **sopra** l'altra: affiancate, ognuna resterebbe stretta e le file si spezzerebbero. La legenda dice ciò che nell'area **c'è**: nelle gallerie non risultano né posti bloccati né posti accessibili, quindi restano *libero* e *assegnato*, e la condizione guarda i posti e non l'area — se il teatro confermerà che esistono (domanda 10) le voci torneranno da sé.
    • **Il posto si assegna alla registrazione** (RF-BO-028, chiude B26). placeOnRegistration colloca il nucleo **nell'atto stesso dell'iscrizione**, sulle poltrone accanto, con le stesse esclusioni di prima valutate su una registrazione sola: non Ospiti, non da inserimento manuale, nessuna segnalazione di accessibilità. Non fallisce mai verso l'esterno — a sala piena la registrazione resta valida e compare fra i «Posto da assegnare» — e scrive l'audit con un attore proprio, **sistema-registrazione**: sulla timeline dev'essere chiaro che il posto l'ha dato il sistema, non una persona che non ha premuto nulla.
    • **Il backoffice dice chi va con chi**, in quattro punti dove un gruppo sarebbe apparso come righe slegate: chi è collegato a un referente **non è più un candidato a sé** e la card del referente porta il badge «*n* adulti del gruppo» accanto a «*n* minori 3–17»; l'elenco ha la colonna **«Gruppo»** — un «Sì» sul referente, il nome del referente sulla riga di chi è stato aggiunto — e si **ordina per gruppo**, referente in testa e membri rientrati sotto un filo verticale; la scheda si intitola **«Gruppo»** invece di «Famiglia» appena c'è un adulto, perché chiamare famiglia tre colleghi sarebbe una parola sbagliata su una schermata che si legge per decidere; l'export CSV guadagna la colonna **«Gruppo di»**, che sulla lista stampata della sera è l'unico modo di sapere chi siede con chi.
    • **Sette casi d'uso UAT nuovi**: configurazione di fase zero, invio Email 2 con la guardia di accessibilità, assegnazione di un nucleo in platea, ripiego in galleria e rientro in platea, proroga di un non confermato, reinvio del biglietto con revoca del QR, batch gallerie e nuclei.

    Modificato

    • **Il nucleo non è più «un adulto e i suoi figli»: è la registrazione.** referentId collegava solo minori, e chi componeva i nuclei risaliva al referente **guardando il tipo** della riga. È bastato togliere quel controllo — il legame diceva già «questa gente si è registrata insieme» — perché tutto il resto seguisse: la collocazione mette il gruppo intero nella stessa galleria su posti contigui, l'invariante di area vale per tutti, lo spostamento di nucleo li muove insieme. **Nessuna regola nuova**: è cambiato *chi* fa parte del nucleo. È anche il punto dove sta il costo vero della registrazione di gruppo — non nel form.
    • **Il settore si comunica al partecipante.** «Galleria 1 · Palchetti sinistra — Fila 11 · Posto 21», perché con i numeri fisici «Fila 11 · Posto 21» da solo indica **due poltrone diverse**. In galleria i laterali si chiamano *palchetti* e non *settore sinistro/destro*: chiamarli col nome della platea manderebbe la persona a cercare una poltrona in mezzo alla fila. Il progressivo resta nell'etichetta solo per le assegnazioni **vecchie**, fatte quando le gallerie non avevano posti: finché esistono in banca dati vanno mostrate, ed è meglio un «Posto n° 12» storico che una riga vuota.
    • **Il dominio assegna poltrone, non progressivi.** La collocazione cerca **posti contigui** — stessa fila, stesso settore, posizioni consecutive — con la stessa regola della platea (RF-BO-046c): un nucleo che non trova un blocco abbastanza lungo passa all'altra galleria e, se neanche lì entra, **resta da collocare invece di spezzarsi**.
    • **Scadenza e proroga cascano su tutta la registrazione.** Conseguenza diretta del clic unico: chi è stato aggiunto **non ha modo di confermarsi da sé**, quindi alla scadenza decade col referente e la proroga lo ripristina con lui — «tutta la registrazione o niente», che prima valeva per la sola famiglia. È il prezzo dichiarato della verifica unica, scritto nei requisiti perché il coordinatore lo sappia prima e non la sera. Nuova azione di audit gruppo.in-attesa, gemella di minore.in-attesa: la timeline di un adulto non può dire «minore».
    • **Rinuncia e annullamento invece *non* cascano sugli adulti**, deliberatamente. La cascata segue la **credenziale**: chi non ha un link proprio dipende dal referente (i minori, come prima), chi ha un **biglietto proprio** decide per sé — l'adulto del gruppo rinuncia solo per sé e, se il referente si sfila, resta seduto. Portargli via il posto significherebbe cancellare il biglietto di qualcuno che non ha fatto niente. Si annulla uno per uno dalla sezione «Gruppo» della scheda.
    • **L'Email 2 non si manda a chi è stato aggiunto.** Un adulto del gruppo un'email ce l'ha, quindi senza guardia sarebbe risultato eleggibile come chiunque altro — e un secondo link di conferma spezzerebbe l'atomicità del nucleo su scadenza e proroga. Il rifiuto vive **nel dominio**, non nell'interfaccia: qualunque percorso ci arrivi — invio massivo, deep-link, URL a mano — trova la stessa risposta. L'email al referente **nomina** chi conferma con lui e dice che ognuno riceverà il proprio biglietto sulla propria casella: è ciò che rende comprensibile il fatto che agli altri, fino a quel momento, non arrivi nulla.
    • **L'azione «Assegna Ospiti alle gallerie» è uscita dall'interfaccia.** Non ha più niente da innescare: la collocazione avviene alla registrazione. L'operazione **resta nel dominio** come rete di recupero, senza pulsante — stessa sorte già toccata a moveGallery nella 0.11.0 — e al suo posto, nella scheda, c'è la mappa.

    Database

    • Migrazione drizzle/20260911150145_posti-gallerie: l'identità di un posto passa da (area, numero) a **(area, fila, settore, numero)**. Con i numeri **fisici** delle balconate il vecchio indice non regge — ogni fila riparte e dentro la stessa fila i palchetti hanno la loro numerazione, tanto che **in G1 fila 11 esistono due posti 21**, uno nel palchetto e uno al centro. È anche la ragione per cui il settore entra nell'indirizzo comunicato al partecipante. Non breaking: la platea numera 1…900 e resta unica anche sotto la chiave più larga.
    • Migrazione drizzle/20260911152810_posto-ordine: nuova colonna **seats.ordine** (integer, nullable), la posizione nella fila **da sinistra**, 1-based. Serve alle gallerie, dove i numeri non crescono da sinistra a destra (i dispari scendono, poi i pari risalgono): senza, «il posto accanto» non sarebbe calcolabile e la mappa non saprebbe in che ordine disegnare la fila. In platea resta nulla, perché lì il numero è già progressivo per posizione.
    • src/lib/server/db/schema.ts aggiornato di conseguenza; il seed statico popola i posti di G1 e G2 da seed/gallerie-layout.json, estratto dalla pianta e committato come dato revisionabile.

    Corretto

    • **Il contatore dei progressivi di galleria era monotòno e non riusava i numeri liberati**: su G1 era arrivato a **463 con 400 posti**. Finché il progressivo era interno non faceva danno; da quando è il numero stampato sul biglietto (RF-BO-029d, 0.11.0) si poteva comunicare una poltrona che in sala **non esiste** — e lo si sarebbe scoperto alla porta. Con i posti veri il contatore non serve più e il difetto sparisce con lui.
    • **Spostarsi *dentro* la stessa galleria falliva contro sé stesso**, bruciando un numero: lo spostamento non considerava libere le poltrone che il nucleo stava lasciando. Ora sì.
    • **Tre test browser della mappa erano rossi**, e due lo erano da prima di questo rilascio: verificavano una conferma a due clic sostituita dalla domanda unica del 03/09 e un filtro professione **tolto** il 02/09 (testo libero del form, la tendina elencava grafie invece di raggruppare persone). Allineati al comportamento vero — il terzo al popover, che ora riceve la collocazione già scritta, settore compreso, invece di comporla da sé scrivendo «Platea» anche in galleria. Rimosso anche galleryRowsOf nel load delle assegnazioni: la mappa condivisa vuole i posti, non le file già raggruppate.
  2. v0.11.0 3 settembre 2026

    Aggiunto

    • **Il batch gallerie tiene fuori chi ha segnalato un'esigenza di accessibilità — e lo nomina** (RF-BO-028d). Il flag dice che *c'è qualcosa da concordare* (RF-FORM-021), e l'accordo si fa per email fuori dalla piattaforma: accorpare queste persone al mucchio degli altri Ospiti significa deciderne la sistemazione prima di sapere di cosa hanno bisogno. Restano registrato e l'esito del batch le elenca **per nome**, una riga per nucleo sul referente, ciascuna cliccabile verso la propria scheda: un contatore direbbe quante sono e non su chi andare (UC18). Il controllo sta **dopo** quelli sull'ancora di proposito — se il nucleo è già in una galleria chi manca la raggiunge lo stesso, altrimenti l'esclusione lascerebbe indietro un minore col padre già seduto. Il riquadro ha la tinta d'attenzione, è staccato dall'esito verde e **non si ritira dopo otto secondi** come gli altri avvisi (RF-BO-051): quella è una coda di lavoro da percorrere clic per clic, e ritirarla mentre il coordinatore ci sta dentro sarebbe il difetto, non la cura.
    • **«Assegna in galleria» dalla scheda** (RF-BO-052), il ripiego del percorso accessibilità. Chi è rimasto fuori dal batch aspetta l'email all'indirizzo dedicato; se quell'email non arriva mai, questo bottone lo tratta come gli altri Ospiti invece di lasciarlo senza posto — e quindi senza Email 2, che al posto è legata. Conferma a due passi con l'avviso esplicito che **in galleria posti accessibili non ce ne sono**: dirlo prima di scriverlo è il minimo. Offerto solo a un registrato con la segnalazione, mai a un minore, che nel nucleo non decide; il messaggio d'esito nomina la galleria e il numero di posto, che è il dato che finirà sul biglietto (RF-BO-029d).
    • **Le note interne hanno un'etichetta nella timeline** (RF-BO-015b): nota.aggiunta e nota.cancellata mancavano da AUDIT_ACTION_LABEL, e senza etichetta la scheda mostrava il codice grezzo in mezzo a righe scritte in italiano. Le due righe restano senza transizione di stato, che è giusto: una nota non muove niente, si aggiunge.
    • **Otto casi di accessibilità nel seed demo**, scelti e non sparsi a percentuale: tutti Ospiti e tutti registrato, perché è esattamente l'elenco che il batch lascia indietro. Cinque adulti soli, uno con un minore sotto i 3 anni, due con minori 3–17 — la proporzione è il punto, se metà della coda avesse minori il caso raro diventerebbe quello normale e la demo insegnerebbe la cosa sbagliata.
    • **Otto nuovi percorsi end-to-end**: esclusione dal batch e assegnazione dalla scheda per l'accessibilità, guardia dell'Email 2, collocazione di un nucleo in platea, cascata di annullamento su una famiglia, note interne (aggiunta, cancellazione, assenza dall'export CSV), pagina account, etichetta di build, sonde di salute live/ready.

    Modificato

    • **assignToGallery accetta area come parametro opzionale**: omessa, sceglie da sé il **primo posto utile** — prima la galleria che contiene il nucleo intero, G1 e poi G2, lo stesso ordine di riempimento del batch. È la forma che serve alla scheda, dove il coordinatore sta rimediando e non sta scegliendo un'area: chiedergliela sarebbe una domanda senza una risposta informata. Se il nucleo è già ancorato in una galleria vince quella, perché ricomporre viene prima dell'ordine di riempimento; ancorato **in platea** l'operazione resta rifiutata, perché quello è uno spostamento (RF-BO-029b), non un'assegnazione. hasAccessibilityRequest entra in Party e si legge sull'intero nucleo: la conseguenza è del nucleo, se c'è qualcosa da concordare si concorda per tutti quelli che viaggiano insieme.
    • **La colonna di galleria è sola lettura.** Ritirato lo spostamento G1↔G2 nella 0.10.0, GalleryCol conservava ancora il form, la destinazione e lo stato che serviva a decidere cosa disabilitare: col bottone se ne va anche quello, e la colonna non fa più POST. Il dominio (moveToGallery) e la form action moveGallery **restano**, senza punto d'ingresso, in attesa della conferma del coordinatore.
    • **Il testo introduttivo del batch dichiara l'esclusione** invece di lasciarla scoprire dall'esito: chi ha segnalato un'esigenza resta fuori, si trova elencato sotto e si colloca dalla sua scheda, uno a uno.
    • **La documentazione recepisce RF-BO-028d e RF-BO-052** — requisiti, casi d'uso, analisi funzionale, punti aperti e domande al coordinatore.

    Corretto

    • **La suite e2e affamava la platea.** Gli end-to-end girano contro il Postgres di sviluppo **condiviso**, che non si azzera fra un giro e l'altro: ogni giro registrava ~20 persone e ne collocava altrettante senza mai liberare i posti. In quattro giri gli occupati sono passati da 225 a 305 su 900 — 196 dei 305 erano righe dei test — e a quel punto gli spec d'integrazione che hanno bisogno di spazio libero hanno cominciato a fallire per accumulo: reverse.spec.ts non trovava più una fila di platea sgombra, party-move.spec.ts non trovava posti adatti. Test rossi per accumulo, non per il codice in prova, e quindi rossi che non puntavano a niente. Un globalTeardown (tests/e2e-teardown.ts) restituisce ora i posti alla sala, cancellando **solo** ciò che la suite crea e riconoscendolo per come lo crea, non per quando: il dominio email @e2e.test.invalid, i minori collegati per referent_id e gli inserimenti manuali senza email, che l'helper marca con un suffisso sul cognome. Nessuna FK è on delete cascade, quindi l'ordine di cancellazione è esplicito; E2E_KEEP_DATA=1 lo salta per ispezionare un giro andato male.
    • **playwright.config.ts mette nero su bianco che la suite non va lanciata con pnpm dev attivo**: dev server e build della suite scrivono nella stessa .svelte-kit/ e si pestano i piedi. Il sintomo non punta alla causa — ERR_MODULE_NOT_FOUND su manifest-full.js cancellato sotto i piedi del prerender, oppure un preview che parte da un build parziale e cade a metà giro lasciando una scia di ERR_CONNECTION_REFUSED che sembrano test rotti. Le porte sono diverse (5173 contro 4173): è la cartella condivisa a fare il danno.

    Database

    • **Nessuna modifica strutturale**: src/lib/server/db/schema.ts e drizzle/** sono invariati dalla 0.10.0.
  3. v0.10.0 3 settembre 2026

    Aggiunto

    • **Collocazione di un nucleo dalla mappa: i minori 3–17 nei posti accanto** (RF-BO-046). Un minore 3–17 è una registrazione a sé, quindi si collocava da solo, tre giri di finestra, scoprendo solo dopo il primo posto se accanto ce n'erano altri. Ora la card dichiara il legame nei due versi — «Con 2 minori 3–17 da sedere accanto» sul referente, «siede con Mario Rossi» sul figlio — e scegliere il referente non assegna: apre la **proposta dei posti accanto**, che una conferma sola colloca insieme. «Accanto» non è numero ± 1: nella pianta del Brancaccio i numeri corrono *attraverso* il corridoio (fila 1: sinistro 1–8, centro 9–20), quindi la ricerca resta dentro **fila e settore** e un test dedicato afferma che una famiglia non venga proposta a cavallo del passaggio. Se i posti non bastano **non si assegna nulla** e si dice quanti liberi si sono trovati: collocare il referente e lasciare indietro i figli è il danno esatto che il vincolo di nucleo esiste per evitare. Modulo puro src/lib/components/adjacent-seats.ts, dieci unit test; i posti ♿ restano fuori dalle proposte automatiche pur essendo assegnabili (RF-BO-032b), perché si concordano, non si riempiono perché capitavano accanto.
    • **Filtro «Richieste»** (RF-BO-008…013, parte mai realizzata): isola le tre segnalazioni dichiarate in registrazione — minore sotto i 3 anni, minori 3–17, accessibilità. Le prime due sono flag di riga; «minori 3–17» è un exists sui figli legati da referentId, quindi seleziona i **referenti** che ne hanno dichiarato almeno uno e non i minori stessi, perché l'unità di lavoro del coordinatore è il nucleo. Vale anche per l'export CSV, che condivide la query. Con questo l'«Accessibilità» di RF-BO-031/032/033 smette di essere una colonna da leggere a occhio. Vocabolario condiviso in src/lib/design/requests.ts, come status.ts per stati e categorie.
    • **Le card in cima alla Dashboard sono i filtri di stato**: la prima è il totale di tutte le richieste di partecipazione arrivate — form pubblico e inserimento manuale — le altre otto sono gli stati del dominio, ciascuna col conteggio sull'intera popolazione. Cliccarne una riscrive il solo ?status=, conserva ricerca/categoria/richiesta e riparte da pagina 1.
    • **Il posto in galleria ha un numero** (RF-BO-029d). Il progressivo era un contatore interno «per QR e monitoraggio», dichiarato mai comunicato — salvo che seatPlacementLabel lo stampava sul biglietto da mesi. Ora è ufficialmente il posto del partecipante e compare anche in backoffice, accanto a ogni nome nelle colonne G1/G2: senza numero, un nucleo che il batch colloca insieme si sparpagliava comunque all'arrivo. I numeri di una famiglia sono **consecutivi** per costruzione, perché il batch colloca i nuclei uno dopo l'altro dal contatore monotòno.
    • **Badge sulle card della finestra di assegnazione** (minore <3, *n* minori 3–17, ♿ accessibilità): quel che cambia la mossa si legge **prima** di scegliere.
    • **Collegamento contestuale alla coda «Non confermati»**, che compare nell'elenco quando il filtro è su quello stato — l'unico momento in cui serve — con il ritorno all'elenco dalla coda. Tolte le sotto-viste a tab, la proroga di RF-BO-040b, che vive **solo** in quella pagina, sarebbe rimasta senza alcun percorso che ci portasse.
    • **Voce di legenda «Accessibile assegnato»** sulla mappa (RF-BO-032c): prima la legenda spiegava il ♿ libero e lasciava indovinare l'altro.
    • **scripts/pulisci-prove.ts**: rimuove dall'ambiente dev il detrito delle prove manuali — registrazioni finte, minori, posti occupati e quanto vi pende. Mirato ai soli cognomi degli script di prova, mai ai dati di collaudo UAT o inseriti da altri; senza --apply elenca e basta.

    Modificato

    • **La finestra di assegnazione diventa una domanda sola** (RF-BO-046b). Al clic la card sale in cima, elenco, ricerca e filtri spariscono, e sotto un divisorio resta una domanda con Annulla a sinistra e Conferma a destra. La domanda cambia col caso e i casi si sommano: un referente con minori *e* segnalazione vede l'elenco dei posti del nucleo insieme alla richiesta di conferma sull'email. Prima la conferma esisteva solo per il ♿, come secondo clic sulla stessa card, mentre i posti del nucleo comparivano in un riquadro sopra l'elenco ancora aperto — due grammatiche per la stessa domanda, e in nessuna delle due si leggeva per intero cosa si stava per assegnare.
    • **I minori 3–17 escono dall'elenco dei candidati** (RF-BO-046c): non vanno a posto da soli, si sceglie l'adulto e vengono con lui. Restano in elenco solo quando il referente ha già un posto, perché lì il nucleo non è più da comporre e nasconderli li renderebbe irraggiungibili. Sparisce anche il deep-link «Assegna posto» dalla scheda di un minore, che li avrebbe portati sulla mappa per poi ignorarli in silenzio.
    • **I posti accanto si prendono alternando i lati**: il posto subito a destra, quello subito a sinistra, poi il secondo a destra. Prima si esauriva un lato e con due minori il referente finiva a un capo del gruppo — accanto a un figlio e separato dall'altro; ora resta **in mezzo ai suoi**, e quando un lato si chiude l'altro prosegue senza buchi. L'elenco della conferma è in ordine di posto, così si legge come la fila reale.
    • **La mappa platea è una volta e mezza più grande**: il posto passa da 16 a 24 px e al 100% si vede quel che prima si vedeva al 150%. Un solo fattore (MAP_BASE_SCALE) moltiplica ogni misura della griglia via la custom property --sc, così le proporzioni non si spostano; l'intervallo dello zoom scende di conseguenza da 60–240% a **40–160%**, quindi le dimensioni raggiungibili a schermo sono le stesse e si sposta solo dove cade l'etichetta. Senza quel secondo passo il vecchio minimo faceva da pavimento al calcolo di adattamento e la mappa si apriva al **doppio** — misurato, non dedotto.
    • **In cima alla Platea tre contatori di sola lettura** — da assegnare, assegnati sul totale, posti liberi — al posto della riga «liberi · assegnati · bloccati»: i bloccati non hanno un numero proprio perché non c'è nulla da farci, restano nel totale e in grigio sulla mappa. Le sottoschede passano da pillole riquadrate a **schede sottolineate**, che accanto alle card-filtro della Dashboard non si leggono più come altri filtri.
    • **L'inserimento manuale non ammette più gli Ospiti** (RF-BO-028c, MANUAL_ENTRY_CATEGORIES): restano stampa, sponsor e istituzioni. Un Ospite arriva dal form pubblico e lo colloca il batch in galleria; ammetterlo qui creava l'unico caso di persona che il batch non prende e che nessuno segnala — restava senza posto e, non essendo assegnata, senza Email 2. [DA CONFERMARE con il coordinatore], v. docs/domande-coordinatore.md.
    • **La selezione per l'Email 2 di massa è ristretta agli stati che il dominio accetta**, Assegnato e In attesa (RF-BO-034…037). Prima si poteva spuntare chiunque non fosse Annullato — un Confermato, un Entrato — e premere «Invia Email 2» per vederseli contare fra i saltati: un'azione offerta che non sarebbe stata eseguita, col conto che arrivava a selezione già fatta. Non confermato resta fuori: alla scadenza il posto è stato liberato, quindi quell'invito chiederebbe di confermare una poltrona che non c'è più — la via è la **Proroga**, che prima ripristina il posto.
    • **Gli avvisi di esito dicono la parola giusta** (RF-BO-050) — «Assegnati» per una prima collocazione, «Spostati» per uno spostamento, perché la stessa operazione serve i due percorsi — portano fila e numero per intero e si ritirano dopo otto secondi; gli errori restano, perché chiedono di fare qualcosa.
    • **La sidebar perde i badge numerici**: un «359» accanto a «Dashboard» e un «40» accanto ad «Assegnazione» non dicevano *di che cosa* fossero il conto, e sospesi lì si leggevano come notifiche da smaltire — i due numeri esistono già dove significano qualcosa, nelle card di stato e nei contatori della Platea. Via con loro le due count(*) che li alimentavano a ogni navigazione. Testo e icone in bianco; icone nuove per Dashboard, Assegnazione e Configurazione.
    • **La scheda Gallerie si ripulisce**: via la heat-grid dei quadratini (resta la barra con la percentuale), via la nota «senza numero di posto» — non più vera — e via la card «Inseriti da te, senza posto», il cui caso non nasce più ora che l'inserimento manuale non ammette Ospiti. Dall'esito del batch cade la riga «N inseriti da te non sono stati toccati», che conterebbe sempre zero.
    • **I controlli di avvio non si attendono più al ricaricamento della configurazione**. Fra essi c'è una chiamata di rete — la discovery OIDC verso Keycloak — e attenderla lì dentro allungava il salvataggio di un parametro: la modifica entrava in vigore solo dopo il round-trip, che con la rete lenta o assente si misura in secondi. La configurazione è già validata; questi sono diagnostica, e la diagnostica non sta sulla strada del lavoro. Restano non fatali e ora girano in background, con l'errore a log.

    Corretto

    • **Il posto ♿ occupato era inamovibile.** Nel markup i rami erano ♿ libero → blocchi invalicabili → assegnato, e un ♿ *occupato* — che ha blockReason = 'accessibile' — cadeva fra i bloccati: reso come uno <span> non cliccabile, con l'occupante impossibile da spostare. Il commento accanto dichiarava l'esclusione, la condizione no; il dominio lo consentiva già. Ora è un assegnato come gli altri, stesso verde, icona ♿ nera, popover «Sposta» (RF-BO-032c).
    • **Un percorso non controllato spezzava i nuclei.** La guardia sui posti del nucleo viveva nella sola finestra di assegnazione, ma il deep-link «Assegna posto» della scheda non ci passa: arma la persona e il clic assegna. Con un referente che porta minori il risultato era il padre su un posto isolato e i figli senza niente. La guardia è stata spostata **nel dominio** (assignPlateaSeatparty_needs_seats): finché restano due o più membri da collocare, nessuno si assegna da solo, da qualunque percorso; con uno solo rimasto tace, altrimenti non ci sarebbe modo di finire il lavoro o di rimediare a una collocazione storta. In parallelo il percorso armato apre la proposta invece di assegnare, perché un rifiuto dopo il clic è una porta sbattuta in faccia, non una guida.
    • **Gli helper e2e scrivevano su un database diverso da quello del server sotto test.** Usavano process.env.DATABASE_URL ?? '…@localhost:5432/app', ma quella variabile non è esportata quando si lancia pnpm test:e2e: il server la legge da .env via dotenvx, il processo di Playwright no. Ora la fonte è la stessa del server.

    Rimosso

    • **Lo spostamento di una persona fra G1 e G2** (RF-BO-029, ritirato). È un requisito canonico, ma nessun documento diceva a quale bisogno rispondesse — né la tabella dei requisiti, né UC13, né l'analisi funzionale: tutti descrivono cosa fa, nessuno perché. E il motivo non è ovvio, perché muovere qualcuno fra due gallerie non migliorava la sua sistemazione: cambiava una parola sul biglietto e bruciava un progressivo. Ritirato dall'interfaccia **col dominio lasciato pronto** (moveToGallery e i suoi test restano, senza punto d'ingresso) e la domanda messa nero su bianco in docs/domande-coordinatore.md: se emerge un caso reale si riaccende, se non emerge si cancella. Sparisce con esso la fonte principale dei buchi nella numerazione dei posti di galleria.
    • **La Panoramica dell'Assegnazione**: era una schermata che si attraversava per arrivare al lavoro vero, la mappa. Restano **Platea** e **Gallerie**, e senza ?tab= si atterra sulla Platea; i vecchi link a ?tab=panoramica ci ricadono invece di dare errore. Esce di scena con lei la striscia «Saturazione aree»: RF-BO-003 resta soddisfatto ma **diviso** fra le due sottoschede, e il colpo d'occhio sulle tre aree insieme non c'è più. AssignmentOverview e CapacityStrip restano nel codice, raggiungibili solo da Storybook.
    • **Il filtro per professione** dalla finestra di assegnazione (RF-BO-046): è testo libero del form pubblico, quindi la tendina elencava le grafie che la gente scrive — «Matematica» e « matematica » erano due voci — invece di raggruppare persone. Restano categoria e accessibilità; la professione si vede sulla card e si cerca dalla ricerca libera. Rimossi con esso il campo dal modello dei filtri e distinctProfessions, coi loro test.
    • **La tendina «Stato» e le due sotto-viste a tab** (Elenco / Non confermati) della Dashboard, sostituite dalle card-filtro: la tendina diceva la stessa cosa con meno informazione. Via anche la vecchia card «Registrazioni totali» — a confondere non era il totale ma il nome, che sembrava parlare dei soli registrato seduti lì accanto — e il sottotitolo sotto il titolo.

    Database

    • **Nessuna modifica strutturale**: src/lib/server/db/schema.ts e drizzle/** sono invariati dalla 0.9.0.
    • Aggiunto **scripts/apply-notes-migration.ts**, che applica la migration drizzle/20260902124535_note-interne (tabella registration_notes) agli ambienti in cui non era mai passata. Il DB di dev nasce da drizzle-kit push, quindi non ha la tabella di bookkeeping drizzle.__drizzle_migrations su cui db:migrate si appoggia; senza registration_notes il load della scheda partecipante falliva e il drawer rispondeva 500. Idempotente — gli oggetti già presenti si saltano — e riusabile sugli altri ambienti nella stessa condizione.
  4. v0.9.0 2 settembre 2026

    Aggiunto

    • **Spostamento di un nucleo dalla galleria alla platea** (UC16, RF-BO-029b/029c). L'Ospite che ha segnalato un'esigenza di accessibilità viene collocato in galleria dal batch come tutti; quando scrive all'indirizzo dedicato, il coordinatore lo sposta in platea **con tutto il suo nucleo** in un atto solo: i posti si scelgono tutti prima e restano «in attesa di conferma» — finché non si conferma, in banca dati non è cambiato nulla — poi una conferma sola li muove insieme. Se un posto risulta occupato alla conferma **non si muove nessuno**. Vale nei due versi e gestisce nello stesso atto chi va spostato e chi riceve la **prima** assegnazione, perché un nucleo con un membro liberato a mano sarebbe altrimenti impossibile da collocare.
    • **Note interne sulla scheda partecipante** (RF-BO-015b): elenco in aggiunta con **autore e momento**, non un campo sovrascrivibile — serve ricostruire *quando* è stato concordato *cosa*. Cancellabili (con la cancellazione in audit, che conserva il testo), **solo backoffice**, mai nell'export CSV, **nessun dato sanitario**: un testo libero nato per l'accessibilità è il punto in cui patologie e diagnosi rientrerebbero dalla porta di servizio. Sono l'unico posto dove può vivere il legame fra un accompagnatore adulto e la persona che assiste, che nessun campo modella.
    • **Assegnazione di una singola persona in galleria** (RF-BO-028c) e pannello **«Inseriti da te, senza posto»**: chi il coordinatore inserisce a mano non entra più nel batch, quindi deve essere visibile — un inserimento non collocato resta senza posto e non può ricevere l'Email 2.
    • **Segnalazione di accessibilità nell'inserimento manuale** (RF-BO-019), che il requisito prevedeva e il form non raccoglieva. Serve all'accompagnatore inserito a mano.
    • **Guardia sull'invio dell'Email 2** a chi ha segnalato un'esigenza ed è ancora in galleria (RF-BO-037b): la conferma che seguirebbe **cristallizza** quel posto, e correggere dopo costa un reinvio biglietto con revoca del QR. Dalla scheda è un avviso che si supera deliberatamente; nell'invio di massa quei destinatari sono **saltati e contati a parte**, con il rimedio giusto a schermo. La proroga eredita la guardia, perché è lo stesso invio.
    • **Area e posto di ogni minore** nella sezione «Famiglia» della scheda: per un vincolo il cui punto è «non lasciarne indietro nessuno», vedere dove sono seduti i figli guardando la scheda del padre è il dato principale della schermata.

    Modificato

    • **Il batch gallerie colloca nuclei interi**, non persone (RF-BO-028b). Un nucleo che non entra nello spazio residuo di G1 va **intero in G2**, e quei posti restano ai nuclei più piccoli che seguono. Prezzo accettato e messo per iscritto: l'ordine di registrazione non è più rispettato in modo stretto, e l'area è un dato che comunichiamo al partecipante. L'esito distingue i motivi di mancata collocazione — gallerie piene, nucleo non capiente, galleria del referente piena — perché un overflow dichiarato mentre a video ci sono posti liberi si legge come un difetto.
    • **Il batch prende solo le registrazioni da form pubblico** (RF-BO-028c): ciò che il coordinatore inserisce a mano lo colloca a mano. Nei nuclei misti decide l'origine del referente.
    • **Lo spostamento G1↔G2 muove il nucleo** quando c'è un nucleo (RF-BO-029): l'azione resta per persona, ma un adulto solo si sposta da sé e un referente con minori porta con sé la famiglia. «Stessa area» vale alla grana esatta: G1 e G2 sono aree diverse, e lasciare indietro un minore reintrodurrebbe la famiglia spezzata che il batch per nuclei esiste per evitare.
    • **I posti ♿ sono sempre assegnabili dal coordinatore** (RF-BO-032b). Restano fuori da ogni automatismo, ma al clic si comportano come posti liberi: supera la formulazione «non assegnabili in qualsiasi circostanza, anche in caso di sold-out», che impediva di registrare a sistema proprio la sistemazione concordata via email. Sulla mappa hanno un aspetto proprio — bordino rosa, fondo grigio scuro, icona bianca — e restano riassegnabili anche da occupati.
    • **La mappa platea si semplifica.** Via la coda laterale «Da assegnare in platea» (ricerca e filtri vivono nella finestra che si apre cliccando il posto), il selettore «Prima il posto / Prima la persona» col suo form fila/numero, le quattro fasce di colore dei posti liberi, i focus di settore e la scelta «Nome intero / Sole iniziali». La mappa occupa tutta la larghezza e si apre **una volta e mezza più grande** del solo adattamento allo schermo: a fit, su 30 file, vinceva l'altezza e i posti restavano minuti. I contatori salgono in cima alla pagina.
    • **L'icona ♿ è un glifo monocromatico** e la stessa in tutta l'app: il carattere è un emoji, che i sistemi disegnano come badge blu col simbolo dentro.
    • **L'inserimento manuale resta agli adulti soli** (RF-BO-016, RF-BO-019 ridotto): qualunque minore al seguito richiede la dichiarazione di responsabilità, e qui non si raccoglie alcun consenso digitale. Un adulto che porta minori passa dal form pubblico.

    Rimosso

    • **La liberazione dei posti, singola e per fila.** Il vocabolario delle operazioni si regge su tre azioni che non la richiedono: *cambio posto* → sposta, *non viene più* → annulla, *ho sbagliato adesso* → «Annulla assegnazione» dell'avviso di successo. Liberare **senza destinazione** era rimasto l'unico modo di spezzare un nucleo e di riesporre un Ospite al batch; e per la fila intera la motivazione scritta — le ondate dopo le scadenze — è già coperta dall'automatismo, che alla scadenza libera i posti da sé. Se la fila intera servisse davvero va rifatta sapendo che spezza i nuclei in blocco: è una domanda aperta col cliente (punto B16), e l'operazione di dominio resta dormiente.

    Corretto

    • **Il posto ♿ non era cliccabile** fuori dal flusso del nucleo, e da occupato cadeva nel ramo dei bloccati: l'occupante non si vedeva e il posto risultava bloccato invece che riassegnabile.
    • **La suite e2e delle registrazioni era rossa dal 31/08**: l'helper cercava la casella «posto accessibile», etichetta cambiata in «Ho un'esigenza di accessibilità» col rename di RF-FORM-021. Corretti anche due locator troppo larghi (Applica, Azioni) che pescavano il selettore di paginazione e l'intestazione delle spunte.
    • **Un test flaky** sull'audit delle note: confrontava la sequenza degli eventi con una query senza order by.

    Database

    • Aggiunta migrazione drizzle/20260902124535_note-interne: nuova tabella registration_notes (id, registration_idregistrations, body, author, author_name, created_at, deleted_at, deleted_by) con indice su registration_id.
    • Aggiornato src/lib/server/db/schema.ts con la tabella e i tipi RegistrationNote / NewRegistrationNote.
    • **Non breaking**: solo aggiunta: nessuna colonna, vincolo o enum esistente è stato modificato. Va comunque applicata prima del deploy, perché la scheda partecipante legge le note a ogni apertura.
  5. v0.8.0 2 settembre 2026

    Aggiunto

    • **Paginazione delle tabelle di backoffice.** src/lib/design/pagination.ts è il vocabolario condiviso — query param (page, per), taglie offerte (10/20/50), aritmetica della finestra di pagine e costruzione degli URL — usato sia dai load (che tagliano la query con limit/offset) sia da Pagination.svelte, che disegna barra, selettore «Righe per pagina» e link. Puro e coperto da pagination.spec.ts: nessuna regola di dominio, solo pagine e URL. Un URL manomesso (per=7, page=-1, page=99) ricade sui valori di partenza o rientra nei limiti, non dà errore.
    • Barra di paginazione su **Registrazioni** e sulla **coda Non confermati**, con storia Storybook (Pagination.stories.svelte) e caso UAT dedicato (uat/use-cases/paginazione-elenco-registrazioni.md).
    • **Annullamento del singolo minore dalla scheda del referente**: nell'elenco «Famiglia» del drawer ogni minore non ancora annullato ha il suo grilletto con conferma a due passi. Se l'adulto non se lo porta più dietro si annulla il minore da solo, senza toccare il referente — la cascata vale in un verso solo. Storia Storybook per lo stato in conferma.
    • Colonna **«Minori 3–17»** nell'elenco Registrazioni, con countMinorsByReferent: una query sull'insieme delle righe a schermo, non una per riga. Conta i minori *indicati*, qualunque sia il loro stato.

    Modificato

    • **L'elenco Registrazioni serve una pagina alla volta** (finding V7 della verifica del 31/08/2026: 208 righe erano 426 KB di HTML, ~3,3 MB proiettati a regime). listRegistrationRows prende una fetta facoltativa e countRegistrationRows conta il risultato filtrato: la stessa query serve la pagina a schermo e l'**export CSV, che resta intero** — si scarica quel che i filtri selezionano, non quel che si vede.
    • La coda Non confermati ordina ora per scadenza **e id**: senza un ordine totale, a parità di scadenza la stessa registrazione poteva comparire su due pagine o su nessuna.
    • «Seleziona tutto» è la **pagina corrente**, non l'intero risultato. Gli id restano selezionati al variare di filtri e pagina, ma contano e si inviano solo quando tornano visibili. Chiudendo la scheda dalla pagina 3 si torna alla pagina 3.
    • **Annullamento di massa rimosso** dalla bulkbar (?/cancelBulk, cancelRegistrations, relative chiavi di traduzione): è un'operazione terminale che si porta dietro i minori collegati senza dirlo. Si annulla una registrazione alla volta, dalla sua scheda. Alla bulkbar resta la sola «Invia Email 2».
    • **Colonne dell'elenco riviste**: via «Professione» e «Data registrazione» — ci sono nella scheda e nell'export, non guidano il lavoro del coordinatore — e la colonna «Minore <3 e accessibilità» si divide nelle due che era, perché sono due domande diverse. Via anche la colonna «Azioni»: le azioni di riga vivono nella scheda.
    • **Caselle di spunta e radio disegnati dall'app**, in src/routes/layout.css e quindi validi in ogni form, tabella o pannello: il border-radius sui controlli nativi è ignorato da ogni browser, e il plugin forms di Tailwind porta un disegno suo fuori dai token. Bordo da 1,5px sul fondo della card, riempimento d'accento e segno in --accent-ink; il trattino della selezione parziale («seleziona tutto» delle tabelle) è disegnato perché il segno nativo non esiste più. Sotto forced-colors torna il controllo nativo, l'unico che il sistema sappia disegnare.
    • Stato d'errore delle caselle: dall'anello esterno a bordo rosso più riempimento tinto, la stessa lingua dei campi di testo, ora che la casella ha un bordo suo.
    • **Testata del form pubblico a due righe con il marchio a destra**: la testata smette di essere centrata — un titolo centrato accanto a un marchio allineato a destra non ha un asse condiviso — e il marchio prende un raggio di 10px, che trasforma il suo fondo bianco in una targa. Le due righe sono due messaggi (registration_masthead_line_1 / _2); registration_title resta intero per il <title>.
    • **Fascia pride da sei bande nette a gradiente continuo**, interpolato in oklab perché in sRGB il tratto verde-blu passa da un teal spento. Stessi sei colori della bandiera, un solo valore per entrambi i temi: la fascia è un segno, non una superficie tematizzata.

    Corretto

    • **WCAG 1.4.3 (contrasto del testo)**: nove riempimenti d'accento dipingevano il testo di bianco fisso — selettore di categoria, pulsanti pericolo pieni, badge «Entrato» pieno, pulsante dello spettro, i due avatar, i pulsantini pericolo del drawer. Sul tema scuro quei riempimenti sono le tinte chiare, dove il bianco stava a 2,2–2,8:1 contro il 4,5:1 che il testo da 14px/600 richiede. Tutti passano a --accent-ink, il cui contrasto su ogni tinta è già sotto contratto in tokens.spec.ts. Il tema chiaro non cambia: lì l'inchiostro è bianco.

    Database

    • Nessuna modifica: né migrazioni in drizzle/** né variazioni a src/lib/server/db/schema.ts.
  6. v0.7.0 1 settembre 2026

    Aggiunto

    • src/lib/styles/tokens.spec.ts: contratto di contrasto verificato da 47 asserzioni — ogni tinta dello spettro e di categoria è controllata a ≥4.5:1 sulla superficie del proprio tema, sia come primo piano (testo, pallino, bordo) sia come riempimento con l'inchiostro del tema sopra; verifica anche che --cat-* e --cat-*-accent restino identici in ogni tema, invariante su cui si appoggia design/status.ts.
    • Casi UAT per percorsi finora scoperti: registrazione-con-minori-e-accessibilita.md, conferma-partecipazione-link.md, rinuncia-partecipante.md.
    • Casi d'uso **UC11–UC15** in docs/casi-uso.md (invio Email 2, reinvio biglietto con revoca del QR, gallerie G1/G2, elenco/filtri/export, configurazione Fase 0): percorsi già realizzati che l'analisi funzionale trattava come righe del §9. I dieci casi esistenti passano da flusso lineare a flusso + varianti + eccezioni, con il comportamento del gruppo famiglia su conferma, proroga e rinuncia.

    Modificato

    • **Ogni tinta esiste ora in due versioni, una per tema.** Prima ne esisteva una sola: le tinte dello spettro erano tarate sul fondo scuro del backoffice e sul chiaro cadevano a 1.8–3.0:1, mentre quelle di categoria erano tarate sul bianco del form e sullo scuro cadevano a 1.9–2.9:1. Introdotto --accent-ink — bianco sul tema chiaro, quasi-nero sullo scuro — che permette a una sola tinta per tema di fare sia da testo sia da riempimento, e color-scheme esplicito su entrambi i temi.
    • Sparita la ragion d'essere delle varianti --cat-*-accent: con l'inchiostro che segue il tema coincidono con la tinta base. I due nomi restano allineati e il valore è ripetuto anziché aliasato, perché un alias dichiarato su :root resterebbe chiaro dentro il sottoalbero .theme-dark della shell di backoffice.
    • **Anello di fuoco pieno al posto di quello traslucido**: da box-shadow al 25–55% dell'accento a outline: 2px solid var(--accent) con stacco di 2px, su chip dei filtri, card candidato, pulsanti della mappa di platea, controlli di zoom e submit. Sui posti della griglia resta un box-shadow (ora pieno): lì lo stacco esterno invaderebbe i posti vicini.
    • Stato d'errore: l'etichetta non si colora più di rosso in Field.svelte e CheckboxField.svelte — l'etichetta dice *quale* campo è, non come sta. Restano rossi il bordo e il messaggio.
    • La nota con l'indirizzo per l'accessibilità è **sempre visibile**, non più condizionata alla spunta: chi ha un'esigenza diversa da un posto — un cane guida, l'ingresso senza gradini — deve trovare il canale prima di decidere se la casella lo riguarda, e la nota stessa dice di spuntarla.
    • Riga del consenso al regolamento: il link «Regolamento di Sala» è ora inline dentro la frase (nuove chiavi registration_room_rules_before / _after, rimossa registration_room_rules_label).
    • Righe dei minori 3–17 impilate anziché affiancate: nella card da 460px le etichette numerate («Cognome del minore 1») spingevano il riquadro oltre i propri bordi. Dal secondo minore in poi una riga di stacco tratteggiata.
    • Rimossa la nota «Obbligatoria per gli Sponsor.» dal campo Azienda ed esplicitato il testo d'aiuto del minore sotto i 3 anni («un solo minore sotto i 3 anni per ogni adulto che si registra»).
    • Documentazione canonica riallineata al costruito: planimetria schematica ed export CSV dichiarati **in v1** (erano ancora [DA CONFERMARE] e «fuori scope v1»), login Staff Ingresso segnato come risolto, §14 riscritto sui punti aperti effettivamente aperti (B2, B4, B14, E1).

    Corretto

    • **WCAG 2.2 SC 2.5.8 (area di tocco 24×24)**: caselle di spunta da 18×18 a 24×24 nel form pubblico e da 16×16 a 24×24 nelle tabelle di backoffice; le etichette, che commutano la casella e sono quindi target a loro volta, portate a line-height/min-height di 24px. Una di queste caselle è un consenso obbligatorio.
    • **WCAG 1.4.11 (contrasto dei componenti non testuali)**: bordo del pulsante «aggiungi minore» e delle chip di focus della mappa da 30–45% a 70% dell'accento — stavano a 2.3–2.9:1, sotto la soglia di 3:1, ed è l'unica cosa che disegna il pulsante; il caso peggiore fra le tre categorie e i due temi è ora 3.34:1.
    • Tabelle di registrazioni e non-confermati: overflow-x: auto al posto di overflow: hidden. Su un portatile da 1440px la tabella è più larga della viewport e le ultime colonne (data, azioni di riga) erano **irraggiungibili**, non solo tagliate.

    Database

    • Nessuna modifica: né migrazioni in drizzle/** né variazioni a src/lib/server/db/schema.ts.
  7. v0.6.0 31 agosto 2026

    Aggiunto

    • Shell dello scanner d'ingresso della serata (/ingresso) con ruolo dedicato staff-ingresso e guardie di rotta (wayfinder «Ingresso della sera», ticket 04), e script idempotente per creare ruolo e account operatori su Keycloak (pnpm kc:staff-ingresso, ticket 08).
    • Azione «libera fila» dalla mappa della platea nel backoffice assegnazioni (wayfinder HiFi ticket 10).
    • Toolkit UAT vendorizzato (uat-setup, uat-author, uat-run, uat-guide), casi d'uso della registrazione e run di collaudo registrati sotto uat/.
    • Opzione di configurazione registration.eventDateLabel (env REGISTRATION_EVENT_DATE_LABEL): data della serata mostrata nella nota sull'età dei minori, configurabile perché ancora un'ipotesi in docs/timeline.md.

    Modificato

    • Form pubblico di registrazione: la sezione «Richieste speciali» è divisa in **«Minori»** e **«Accessibilità»** — la prima raccoglie dichiarazioni su chi si porta con sé, la seconda una richiesta, e «speciali» accanto alla disabilità è terminologia da evitare.
    • Testi del riquadro Minori riscritti: le due caselle rispondono alle stesse domande (posto? biglietto?) con la stessa struttura, senza gergo interno («per registrazione», «adulto referente», «QR personale», «posto assegnato») e senza maschile generico — «bambino» diventa «minore», termine epiceno.
    • **Confini d'età dei minori: «sotto i 3 anni» e «dai 3 ai 17 anni»** (erano «sotto i 3» e «tra 4 e 18»). Il vecchio intervallo lasciava scoperti i treenni e includeva i diciottenni, che sono maggiorenni. L'età si conta alla data della serata. [DA CONFERMARE col Teatro Brancaccio — punto aperto B14]
    • La casella dell'accessibilità passa da «Richiedo un posto accessibile» a **«Ho un'esigenza di accessibilità»**, così da coprire anche ingresso senza gradini, cane guida, accompagnatore; alla spunta compare la nota con l'ordine delle operazioni e il contatto email. Di conseguenza le diciture di backoffice e assegnazione dicono «esigenza di accessibilità» e non più «richiede un posto accessibile».
    • Accento della categoria **Stampa dal rosso al blu** della fascia pride: con gli asterischi e gli errori sempre rossi, in Stampa l'intero form prendeva il colore dell'allarme.
    • Segnali di obbligatorietà uniformi: asterischi sempre rossi (non più tinti dalla categoria) e stato d'errore che colora bordo, etichetta e messaggio in tutti i form dell'applicazione.
    • Rimosse le note «Facoltativa.» dai campi non obbligatori: il form dichiara già in apertura che i campi con * sono obbligatori.
    • Backoffice: colonna «Richieste speciali» → «Minore <3 e accessibilità», tag «Minore 4–18» → «Minore 3–17» (anche nell'export CSV), scheda partecipante allineata.
    • Palette di categoria di docs/design-system.html riallineata al codice: via la categoria «Talent», fuori dalla v1, e nota che le Istituzioni entrano solo per inserimento manuale.

    Corretto

    • **Dichiarazione di responsabilità genitoriale mancante col solo minore sotto i 3 anni**: la casella viveva dentro il blocco dei minori 4–18 e la regola server contava solo quelli, quindi si poteva registrare un adulto con un bambino al seguito senza alcuna dichiarazione (RF-FORM-020).
    • Righe dei minori senza validazione progressiva: nome e cognome bloccavano l'invio ma non mostravano l'errore sul campo, e il server restituiva un solo codice per l'intero blocco senza dire quale riga fosse incompleta. Gli errori sono ora per riga, anche senza JavaScript.
    • Blocco al submit invisibile: quando a fermare l'invio era la validazione nativa del browser non compariva alcun riepilogo, perché era legato alla risposta del server. Ora ogni campo obbligatorio mancante si accende insieme agli altri.
    • Etichette dei campi minore duplicate: le righe sono numerate («Nome del minore 1», «Nome del minore 2»), che risolve anche la lettura da screen reader con più minori.
    • Pulsante «Aggiungi un minore» indistinguibile da «Rimuovi»: ora prende l'accento della categoria.

    Database

    • Nessuna modifica di struttura. src/lib/server/db/schema.ts è stato toccato nei soli commenti (allineamento della dicitura «minori 4–18» → «3–17»); nessuna migrazione aggiunta o modificata in drizzle/.
  8. v0.5.1 23 luglio 2026

    Modificato

    • Aggiornata ROADMAP.md con promozione delle voci completate a release 0.5.0 (data e versione) e riallineamento degli stati in elenco.
    • Aggiornato .dockerignore con eccezione !ROADMAP.md per includere la roadmap nel contesto build Docker.
  9. v0.5.0 22 luglio 2026

    Aggiunto

    • Pagina Roadmap (/roadmap) che rende ROADMAP.md come vista per stato di avanzamento (rilasciato / in sviluppo / da fare / da confermare / dopo la v1), con versione e data di rilascio per le feature già consegnate; nuovo virtual module virtual:roadmap (plugin raw-markdown generalizzato con virtual:changelog), parser src/lib/roadmap.ts con test, card e link nell'hub di sviluppo.
  10. v0.4.0 21 luglio 2026

    Modificato

    • Mappa della platea in backoffice allineata alla pianta ufficiale del Teatro Brancaccio: file dritte (rimossa la curvatura parabolica), fasce di prezzo (Poltronissima Gold, Poltronissima, Poltrona A, Poltrona B) come tinta dei posti liberi, stacco verticale tra blocchi di 10 file, numero di fila visibile nei corridoi e legenda aggiornata (PlateaMap, platea-map-view, traduzioni messages).
    • Aggiornati test e story di PlateaMap per riflettere la nuova geometria e le fasce.
  11. v0.1.10 20 luglio 2026

    Aggiunto

    • Flusso di rinuncia (UC06): annullo di una registrazione tramite token sicuro, stato rinunciato e rilascio del posto assegnato.
    • Reinvio biglietto: richiesta di reinvio del biglietto via email per registrazioni confermate.
    • Gestione minori 4–18: un referente adulto può dichiarare minori al seguito, con finestra di registrazione per categoria e accettazione della responsabilità genitoriale/tutoria.
    • Export CSV essenziale dell'elenco registrazioni, coerente con i filtri correnti della vista backoffice (B10).
    • Finestre di registrazione per categoria nel form pubblico.
    • Suite di test unitari ed e2e per famiglie, finestre, rinuncia, conferma ed export CSV.

    Modificato

    • Aggiornati i template email confirmation-request e ticket-delivery per supportare reinvio e gestione referente/minori.
    • Rifattorizzate e arricchite le operazioni di dominio in src/lib/server/registrations/ (create, confirm, cancel, extend, renounce, resend-ticket, family, timeout, export-csv).
    • Interfaccia backoffice Registrazioni aggiornata con drawer partecipante, azioni di rinuncia/reinvio e pulsante di export.

    Database

    • Aggiunta migrazione drizzle/20260718205511_minori-dichiarazione.
    • Aggiunta colonna minor_responsibility_accepted alla tabella registrations in src/lib/server/db/schema.ts (default false, NOT NULL); obbligatoria per i referenti che dichiarano minori 4–18.
  12. v0.1.9 17 luglio 2026

    Modificato

    • Routine patch release; no functional changes.
  13. v0.1.8 17 luglio 2026

    Aggiunto

    • Favicon e apple-touch-icon del portale prese dal sito Rainbow Awards (https://www.rainbowawards.it/wp-content/uploads/2023/11/favicon-300x300.png); asset servito da static/favicon.png e link in src/app.html.

    Modificato

    • Aggiornamento dipendenze di sviluppo e runtime (Biome 2.5.4, SvelteKit 2.69.3, Svelte 5.56.6, TypeScript 6.0.3, TailwindCSS 4.3.3, Storybook 10.5.2, ecc.) con relativo aggiornamento di pnpm-lock.yaml e pnpm-workspace.yaml.

    Corretto

    • Migrazione di biome.json allo schema 2.5.4 per allinearsi alla versione installata di Biome.
  14. v0.1.7 16 luglio 2026

    Aggiunto

    • Vista Gallerie (wayfinder ticket 09): nuovo GalleryCol.svelte con testata occupati/capienza, heat-grid decorativa, fill bar, lista assegnati e bottone di spostamento manuale G1↔G2; nuova operazione di dominio moveToGallery in src/lib/server/assignments/galleries.ts (rilascia + riassegna nella stessa transazione, capienza calcolata escludendo l'assegnazione attiva della registrazione stessa).
    • Layout a subtab Panoramica/Platea/Gallerie per la schermata di Assegnazione (wayfinder ticket 08): SubTabs.svelte (tab-link deep-linkabili ?tab=, roving tabindex) e AssignmentOverview.svelte (saturazione aree + CTA Platea/Gallerie).
    • Indicatore di versione/build (tag di release, DEV, o short SHA) nel footer della sidebar del backoffice e nell'hub di sviluppo, tramite resolveBuildLabel e il componente BuildLabel.

    Modificato

    • Rimosso AssignedList (+ story): gli assegnati si vedono ora su mappa/gallerie/drawer.
    • e2e di Assegnazione serializzati (workers: 1) per evitare contese sul batch gallerie globale.
  15. v0.1.6 16 luglio 2026

    Corretto

    • vite.config.ts: il plugin changelog-raw gestisce ora l'assenza di CHANGELOG.md restituendo un contenuto di fallback, evitando errori in fase di build.
    • Spostata la direttiva /// <reference path="./src/virtual-modules.d.ts" /> all'inizio di vite.config.ts per rispettare la posizione corretta delle direttive del compilatore.

    Modificato

    • vite.config.ts: reso il percorso di CHANGELOG.md una costante top-level nel file di configurazione.
  16. v0.1.5 16 luglio 2026

    Aggiunto

    • Virtual module virtual:changelog per servire CHANGELOG.md come stringa raw a build time, evitando che mdsvex lo tratti come componente Svelte nella route /changelog.
    • Dichiarazione di tipo src/virtual-modules.d.ts per il modulo virtual:changelog.

    Modificato

    • src/routes/changelog/+page.server.ts importa ora virtual:changelog invece di CHANGELOG.md?raw.
    • vite.config.ts: registrato il plugin changelogRawPlugin nell'array dei plugin Vite.
  17. v0.1.4 15 luglio 2026

    Aggiunto

    • Home/landing page (/) con logo, wordmark, fascia arcobaleno e hub di navigazione verso le sezioni pubbliche, di backoffice e di sistema (strumento temporaneo di sviluppo).
    • Pagina Changelog (/changelog) che rende CHANGELOG.md come timeline delle versioni, coerente con il design system.

    Modificato

    • Pagina Account (/account) ridisegnata: intestazione profilo con avatar e iniziali, ruoli come chip con descrizione dei permessi, scheda dettagli (nome, email, ID applicativo, identità IdP) e scorciatoia al backoffice.
  18. v0.1.3 15 luglio 2026

    Aggiunto

    • Added Kubernetes manifests for dev deployment under k8s/base and k8s/overlays/dev (Deployment, Service, Secret, Kustomization, Istio Gateway/VirtualService, cert-manager Certificate, namespace transformer).

    Modificato

    • Updated dev overlay database URL to postgres://rainbow_awards_dev_crud:1vW4bM8O5wylIBL.xfPWTxSr@192.168.128.50:5432/rainbow-awards-dev.
    • Aligned dev overlay OIDC configuration with local development settings (issuer https://auth.iad2.click/realms/rainbow-awards, clientId backstage).
  19. v0.1.1 13 luglio 2026

    Modificato

    • Dockerfile: set LOADER_THROW=false during build to prevent yamlLoader errors when .app.yaml is absent.
    • Bumped project version from 0.1.0 to 0.1.1 in package.json.
  20. v0.1.0 13 luglio 2026

    Aggiunto

    • Added release automation skill at .agents/skills/release/SKILL.md for local MINOR bump, checks, build, commit, and tag preparation.

    Modificato

    • Bumped project version from 0.0.0 to 0.1.0 in package.json.
enit