ff
This commit is contained in:
@@ -0,0 +1,6 @@
|
|||||||
|
STS Lab Srl — Spec-Driven Reader (skill per Claude Code)
|
||||||
|
Copyright (c) 2026 STS Lab Srl. Tutti i diritti riservati.
|
||||||
|
|
||||||
|
Questa skill (SKILL.md, references/, scripts/) è di proprietà di STS Lab Srl.
|
||||||
|
L'uso è riservato a STS Lab Srl, ai suoi collaboratori e ai clienti autorizzati.
|
||||||
|
Non è consentita la ridistribuzione o la modifica senza autorizzazione scritta di STS Lab Srl.
|
||||||
@@ -0,0 +1,248 @@
|
|||||||
|
---
|
||||||
|
name: sts-spec-driven
|
||||||
|
description: "STS Lab Srl — Spec-Driven Reader. Legge e SCRIVE la documentazione spec-driven di un progetto (cartella docs/ con PROJECT_MEMORY, REQUIREMENTS REQ-*, specifiche SPEC-*, task T-*, decisioni D-*, difetti DIF-*, TRACEABILITY, TODO, DECISIONS, CHANGELOG, DEVELOPMENT_LOG). Lettura: trasforma la documentazione in un brief di implementazione prima del codice e chiude il ciclo dopo. Scrittura: se il progetto non ha documentazione la crea da zero facendo scegliere fra layout strutturato (00-INDEX + 01-product…08-project) e piatto, con modelli, intervista e controllo di coerenza; aggiunge nuove spec, requisiti e decisioni a una documentazione esistente. Usala all'inizio di ogni sessione di sviluppo, quando l'utente cita un ID (REQ-, SPEC-, T-, D-, DIF-), chiede di implementare una spec o un task, chiede «leggi la documentazione», «da dove riprendo», «che stato ha il progetto», «crea la documentazione», «imposta lo spec driven», «scrivi la spec di …», «nuovo progetto», o quando si inizia a sviluppare in un progetto senza docs/."
|
||||||
|
---
|
||||||
|
|
||||||
|
# Spec-Driven Reader — STS Lab Srl
|
||||||
|
|
||||||
|
> **STS Lab Srl** · Skill proprietaria per lo sviluppo software guidato da specifiche.
|
||||||
|
> © 2026 STS Lab Srl — tutti i diritti riservati.
|
||||||
|
|
||||||
|
Nei progetti STS Lab la documentazione **precede** il codice e ne è il contratto:
|
||||||
|
|
||||||
|
```
|
||||||
|
REQ-xxx cosa deve fare il prodotto (REQUIREMENTS)
|
||||||
|
▼
|
||||||
|
SPEC-xxx come lo fa: API, dati, regole, (03-specs/ o documenti di modulo)
|
||||||
|
│ errori, criteri di accettazione
|
||||||
|
▼
|
||||||
|
T-xxx unità di lavoro implementabile (TODO)
|
||||||
|
▼
|
||||||
|
codice + test
|
||||||
|
▼
|
||||||
|
TRACEABILITY chiude il cerchio: ogni REQ ha spec, task e test che passano
|
||||||
|
```
|
||||||
|
|
||||||
|
Ogni scelta strutturale è una decisione numerata `D-xxx`; ogni difetto noto è un `DIF-xx`.
|
||||||
|
Questa skill serve a **scrivere** quella catena quando manca, a **leggerla bene** prima di
|
||||||
|
toccare il codice, e a **richiuderla** dopo.
|
||||||
|
|
||||||
|
### Quale modalità
|
||||||
|
|
||||||
|
| Situazione | Modalità | Dove |
|
||||||
|
|---|---|---|
|
||||||
|
| Il progetto **non ha** documentazione spec-driven (o l'utente chiede di crearla) | **Scrittura** | §A qui sotto + [references/scrittura.md](references/scrittura.md) |
|
||||||
|
| C'è solo lo scheletro, con molti `DA COMPILARE` | **Scrittura** (completamento) | idem, dallo step in corso |
|
||||||
|
| Serve una spec, un requisito o una decisione **nuovi** | **Scrittura** (aggiunta) | [references/scrittura.md](references/scrittura.md) §6 |
|
||||||
|
| La documentazione c'è e si deve sviluppare | **Lettura** | §1–§8 |
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 0. Strumento: `scripts/spec_index.py`
|
||||||
|
|
||||||
|
Libreria standard Python 3.8+. Usalo **prima** di aprire i file grandi: DECISIONS e
|
||||||
|
DEVELOPMENT_LOG possono superare le 3–6 000 righe e non vanno mai letti interi.
|
||||||
|
|
||||||
|
```bash
|
||||||
|
S=~/.claude/skills/sts-spec-driven/scripts/spec_index.py
|
||||||
|
# lettura (non scrive nulla)
|
||||||
|
python $S overview <docs> # layout, documenti chiave, stato delle spec, segnaposto
|
||||||
|
python $S context <docs> SPEC-004 # definizione + ID collegati + TODO + TRACEABILITY
|
||||||
|
python $S find <docs> D-014 # dove è definito e chi lo cita
|
||||||
|
python $S check <docs> # coerenza: orfani, requisiti scoperti, derive di stato
|
||||||
|
python $S next-id <docs> SPEC|D|DIF|T|REQ [--area AUT] [--spec SPEC-004] [--prefisso W]
|
||||||
|
# scrittura (non sovrascrive mai un file esistente)
|
||||||
|
python $S scaffold <docs> --layout strutturato|piatto --progetto "Nome"
|
||||||
|
python $S new-spec <docs> --titolo "Titolo" [--prefisso W (solo layout piatto)]
|
||||||
|
```
|
||||||
|
|
||||||
|
Su Windows da PowerShell il `~` non viene espanso: usa `$HOME\.claude\skills\sts-spec-driven\scripts\spec_index.py`
|
||||||
|
(oppure lancialo dal tool Bash, dove `~` funziona).
|
||||||
|
|
||||||
|
- Per una SPEC, `context` stampa l'indice delle sezioni con i numeri di riga: leggi poi solo
|
||||||
|
le sezioni che servono con `Read offset/limit`.
|
||||||
|
- `check` esce con codice 1 se trova problemi; riporta all'utente cosa ha trovato.
|
||||||
|
|
||||||
|
Se Python non c'è, ripiega su `Grep` con il pattern
|
||||||
|
`REQ-[A-Z]+-\d+|SPEC-\d{3}|T-[A-Z]{0,2}\d+|D-\d{3}|DIF-\d+` e copia a mano i modelli da
|
||||||
|
`templates/`.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## A. Scrittura — creare la documentazione
|
||||||
|
|
||||||
|
Procedura completa in [references/scrittura.md](references/scrittura.md). In sintesi:
|
||||||
|
|
||||||
|
1. **Verifica** che non esista già (§1). Se esiste solo in parte, non ricrearla: completala.
|
||||||
|
2. **Fai scegliere il layout all'utente** con `AskUserQuestion`, mettendo per primo con
|
||||||
|
«(Consigliato)» quello adatto — *Strutturato* per progetti con più moduli, integrazioni,
|
||||||
|
riscritture, committente esterno; *Piatto* per progetti piccoli, prototipi, un solo modulo.
|
||||||
|
Chiedi anche dove crearla (default `docs/` alla radice del repository).
|
||||||
|
3. **Crea lo scheletro** con `scaffold`. I modelli stanno in `templates/strutturato/`,
|
||||||
|
`templates/piatto/`, `templates/spec.md`, `templates/modulo.md`.
|
||||||
|
4. **Raccogli le informazioni**: prima leggi README, manifest, codice; poi intervista l'utente
|
||||||
|
(al massimo 4 domande per giro, solo ciò che manca). Se c'è codice senza documenti,
|
||||||
|
ricostruisci i requisiti dal codice come tipo **P** con *Origine* `file:funzione`.
|
||||||
|
5. **Scrivi nell'ordine degli step** (visione → requisiti → architettura → spec → contratto e
|
||||||
|
dati → devops → qualità e backlog), con un riepilogo e la conferma dell'utente a fine step.
|
||||||
|
6. **Nuove spec** con `new-spec`: numerazione, blocco di task e lettera dei criteri sono
|
||||||
|
automatici. Nascono sempre «da approvare».
|
||||||
|
7. **Chiudi** con `check` e riporta l'esito.
|
||||||
|
|
||||||
|
Regole che non si derogano:
|
||||||
|
|
||||||
|
- **Non inventare**: ciò che non è noto resta `DA COMPILARE` o diventa una domanda.
|
||||||
|
- **Mai approvare da solo**: una spec diventa *Approvata* solo dopo un sì esplicito
|
||||||
|
dell'utente (procedura in scrittura.md §5).
|
||||||
|
- **Mai sovrascrivere** documenti esistenti; i contenuti sparsi si spostano nei documenti
|
||||||
|
giusti, con l'accordo dell'utente.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 1. Trovare la documentazione
|
||||||
|
|
||||||
|
Cerca nell'ordine: `docs/`, `src/docs/`, `*/src/docs/`, `documentation/`. Una cartella è
|
||||||
|
spec-driven se contiene almeno `PROJECT_MEMORY.md` o `00-INDEX.md` più uno fra `DECISIONS.md`,
|
||||||
|
`TODO.md`, `REQUIREMENTS.md`. Leggi anche `CLAUDE.md`/`README.md` alla radice del repository:
|
||||||
|
possono indicare la cartella o regole locali.
|
||||||
|
|
||||||
|
**Se non la trovi**, non scrivere codice: di' all'utente che il progetto non ha documentazione
|
||||||
|
spec-driven e proponi di crearla (§A). Se l'utente preferisce procedere senza, rispetta la
|
||||||
|
scelta e annotala nella risposta.
|
||||||
|
|
||||||
|
Due layout ricorrenti (dettagli in [references/layout.md](references/layout.md)):
|
||||||
|
|
||||||
|
| Layout | Riconoscimento | Esempio |
|
||||||
|
|---|---|---|
|
||||||
|
| **Strutturato** | cartelle `01-product/ … 08-project/`, `00-INDEX.md`, `03-specs/SPEC-xxx-*.md` | `KadeonCad_v2/docs` |
|
||||||
|
| **Piatto** | tutti i `.md` in una cartella, specifiche come documenti di modulo (`CAD_MODULE.md`, `whatsapp/DESIGN.md`) | `Kadeon/kadeon/src/docs` |
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 2. Lettura di inizio sessione (sempre, prima del codice)
|
||||||
|
|
||||||
|
1. **`overview`** con lo script.
|
||||||
|
2. **`PROJECT_MEMORY.md`** — per intero. Contiene ciò che non è deducibile dal codice e che, se
|
||||||
|
dimenticato, fa ripetere errori: vincoli non negoziabili, azioni pendenti di sicurezza, «le
|
||||||
|
cose da non dimenticare mai». Tienile presenti per tutta la sessione.
|
||||||
|
3. **`00-INDEX.md`** (layout strutturato) — tabella degli step, stato dell'implementazione e i
|
||||||
|
riquadri `> **Titolo (data):**` in testa: sono le novità più recenti, in ordine inverso.
|
||||||
|
4. **Indice di `DECISIONS.md`** — solo la tabella iniziale; le singole decisioni si leggono
|
||||||
|
quando servono.
|
||||||
|
5. **`TODO.md`** — sezione «fuori sequenza / prima di tutto» e la fase corrente.
|
||||||
|
|
||||||
|
Non leggere CHANGELOG, DEVELOPMENT_LOG, openapi.yaml per intero: si interrogano per ID o data.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 3. Prima di implementare: il cancello
|
||||||
|
|
||||||
|
Rispondi a queste domande **prima** di scrivere una riga. Se una risposta è «no», fermati e
|
||||||
|
dillo all'utente.
|
||||||
|
|
||||||
|
| # | Domanda | Dove si verifica | Se «no» |
|
||||||
|
|:-:|---|---|---|
|
||||||
|
| 1 | Il lavoro richiesto corrisponde a un `T-xxx`? | TODO, sezione *Task* della spec | Proponi il task e la spec di appartenenza |
|
||||||
|
| 2 | Il task appartiene a una `SPEC-xxx` in stato **Approvata**? | riga `Stato:` della spec, 00-INDEX | Non implementare: segnala lo stato (*da approvare*, 🟡) e chiedi |
|
||||||
|
| 3 | Le dipendenze del task (colonna *Dipende da*) sono ✅? | TODO, tabella task della spec | Segnala l'ordine corretto |
|
||||||
|
| 4 | Nessuna decisione `D-xxx` **accettata** lo vieta o lo vincola diversamente? | DECISIONS (per ID), PROJECT_MEMORY | Cita la decisione; una deviazione richiede una nuova `D-xxx` |
|
||||||
|
| 5 | Se tocca un requisito di **parità** (tipo `P`) cambia il comportamento? | REQUIREMENTS, colonna *Tipo* | È una decisione di prodotto: serve una `D-xxx` |
|
||||||
|
| 6 | Contratto API e schema dati sono già scritti? | `openapi.yaml` / API.md, DATABASE.md | Si scrive prima il contratto (contract-first) |
|
||||||
|
|
||||||
|
Eccezione legittima: richiesta esplicita dell'utente di procedere comunque. In quel caso
|
||||||
|
procedi, ma registra la deviazione (vedi §6) — è ciò che i progetti chiamano «inversione»
|
||||||
|
e che va lasciata scritta.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 4. Leggere una spec
|
||||||
|
|
||||||
|
Struttura tipica di una `SPEC-xxx` (le sezioni possono variare):
|
||||||
|
|
||||||
|
1. Intestazione: `Stato`, versione, data, **requisiti coperti**, decisione di riferimento.
|
||||||
|
2. Contesto e obiettivo — il *perché*; spesso contiene un dato misurato che giustifica la scelta.
|
||||||
|
3. «Cosa cambia rispetto a ciò che è già scritto» — elenco dei punti fermi che la spec modifica.
|
||||||
|
4. Regole / algoritmo in **forma normativa**: le parole in grassetto e i «**non**» sono vincoli.
|
||||||
|
5. Contratto API: rotta, ingresso, uscita, **tabella degli esiti con codici HTTP**.
|
||||||
|
6. Errori.
|
||||||
|
7. **Criteri di accettazione** (`D1…D12`, `P1…P24`, …): ognuno diventa almeno un test.
|
||||||
|
8. **Task** con dipendenze.
|
||||||
|
|
||||||
|
Regole di lettura:
|
||||||
|
|
||||||
|
- Leggi la spec **intera** quando la implementi; usa l'indice di `context` per le altre.
|
||||||
|
- I paragrafi «è una decisione, non una dimenticanza» descrivono comportamenti voluti che
|
||||||
|
sembrano bug: non «correggerli».
|
||||||
|
- Sezioni con suffisso `bis`/`ter` (es. §5.3bis) sono aggiunte successive: leggile, spesso
|
||||||
|
modificano la regola base.
|
||||||
|
- Per ogni `REQ-` citato leggi la riga in REQUIREMENTS: colonna **Tipo** (P parità / C
|
||||||
|
correzione / N nuovo) e **Origine** (per i `P` la fonte di verità è il codice della versione
|
||||||
|
precedente indicato lì).
|
||||||
|
- Per ogni `D-` citata leggi **solo** la sezione `## D-xxx` (Contesto → Decisione →
|
||||||
|
Alternative → Conseguenze). Una decisione *Superata da D-yyy* non vale più: segui D-yyy.
|
||||||
|
- Il glossario (`GLOSSARY.md`) fissa i termini: usa gli stessi nomi nel codice e nei messaggi.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 5. Il brief di implementazione
|
||||||
|
|
||||||
|
Prima di scrivere codice, presenta all'utente un brief compatto con il modello in
|
||||||
|
[references/brief-template.md](references/brief-template.md): obiettivo, stato della spec,
|
||||||
|
requisiti, regole normative, contratto, criteri di accettazione → test, task e dipendenze,
|
||||||
|
decisioni vincolanti, file di codice probabilmente toccati, **incoerenze trovate**.
|
||||||
|
|
||||||
|
Per un task piccolo il brief può stare in poche righe; non saltare mai le sezioni *criteri* e
|
||||||
|
*incoerenze*.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 6. Dopo l'implementazione: chiudere il ciclo
|
||||||
|
|
||||||
|
Aggiorna la documentazione **nella stessa modifica del codice**, seguendo
|
||||||
|
[references/chiusura-ciclo.md](references/chiusura-ciclo.md). In sintesi:
|
||||||
|
|
||||||
|
| Documento | Cosa scrivere | Quando |
|
||||||
|
|---|---|---|
|
||||||
|
| TODO | stato del task (⬜ → 🟡 → ✅) | ✅ solo con test passanti |
|
||||||
|
| TRACEABILITY | stato della riga REQ, criteri coperti | **quando il test passa, non quando il codice è scritto** |
|
||||||
|
| spec | nuove sezioni `bis`, criteri e task aggiunti | se la regola cambia o si estende |
|
||||||
|
| DECISIONS | nuova `D-xxx` (mai modificarne una vecchia: la si *supera*) | ogni scelta strutturale o deviazione |
|
||||||
|
| CHANGELOG | cosa cambia **per chi usa il prodotto** | ogni modifica visibile |
|
||||||
|
| DEVELOPMENT_LOG | cosa si è scoperto e **perché** si è deciso così | scoperte, tentativi respinti, misure |
|
||||||
|
| PROJECT_MEMORY | solo ciò che, dimenticato, fa ripetere un errore | raramente |
|
||||||
|
| 00-INDEX | riquadro `> **Titolo (data):**` in testa + date «Ultimo aggiornamento» | ogni consegna rilevante |
|
||||||
|
|
||||||
|
Riporta sempre il numero di test eseguiti e il loro esito reale (es. «backend 614 (+3)»).
|
||||||
|
Non dichiarare ✅ ciò che non è stato verificato: scrivi 🟡 e cosa manca.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 7. Incoerenze e fonti di verità
|
||||||
|
|
||||||
|
La documentazione viva va in deriva: indici non aggiornati, totali vecchi, spec marcata «da
|
||||||
|
approvare» ma task già ✅, ID citati e mai definiti (l'`overview` li elenca). Quando le trovi:
|
||||||
|
|
||||||
|
1. **Non correggere in silenzio e non sceglierne una a caso.** Elencale nel brief.
|
||||||
|
2. Applica la gerarchia delle fonti di verità dichiarata dal progetto. Default:
|
||||||
|
- contratto API → `openapi.yaml` (non API.md, non il codice);
|
||||||
|
- requisiti di parità → codice della versione precedente citato in *Origine*;
|
||||||
|
- stato «verificato» → test **eseguiti** (non la TRACEABILITY);
|
||||||
|
- decisioni → l'ultima `D-xxx` accettata che non è superata;
|
||||||
|
- stato di una spec → la sua riga `Stato:`; in assenza, l'indice.
|
||||||
|
3. Se l'incoerenza blocca il lavoro, chiedi all'utente; altrimenti prosegui e proponi la
|
||||||
|
correzione documentale insieme alla consegna.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 8. Cose da non fare
|
||||||
|
|
||||||
|
- Implementare da una spec *da approvare* o da un'idea non scritta, senza dirlo.
|
||||||
|
- «Modernizzare» ciò che un requisito di parità o una decisione congela.
|
||||||
|
- Rinumerare o riusare un ID: gli ID sono **immutabili**; quelli eliminati si barrano (`~~T-005~~`).
|
||||||
|
- Cancellare una decisione o una voce di diario: si superano o si annotano.
|
||||||
|
- Leggere per intero file da migliaia di righe quando basta una sezione.
|
||||||
|
- Copiare segreti trovati nella documentazione in risposte, log o commit.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
<sub>**STS Lab Srl** · Spec-Driven Reader v1.1 (lettura + scrittura) · 2026-10-16 · uso interno e per i clienti STS Lab Srl</sub>
|
||||||
@@ -0,0 +1,42 @@
|
|||||||
|
# Modello — Brief di implementazione (STS Lab Srl)
|
||||||
|
|
||||||
|
Da presentare all'utente **prima** di scrivere codice. Ogni affermazione porta il riferimento
|
||||||
|
`file:riga` o l'ID da cui viene. Togli le sezioni vuote, mai *Criteri* e *Incoerenze*.
|
||||||
|
|
||||||
|
```markdown
|
||||||
|
## Brief · <T-xxx / SPEC-xxx> — <titolo breve>
|
||||||
|
*STS Lab Srl · Spec-Driven Reader*
|
||||||
|
|
||||||
|
**Obiettivo** — una frase: cosa cambia per chi usa il prodotto.
|
||||||
|
|
||||||
|
**Cancello**
|
||||||
|
| Verifica | Esito |
|
||||||
|
|---|---|
|
||||||
|
| Spec | SPEC-xxx · Stato: Approvata v1.0 (03-specs/SPEC-xxx.md:3) |
|
||||||
|
| Task | T-xxx · ⬜ · dipende da T-yyy ✅, T-zzz 🟡 |
|
||||||
|
| Decisioni vincolanti | D-0nn (sintesi in una riga) |
|
||||||
|
| Parità | REQ-ABC-01 è **P**: comportamento da riprodurre identico |
|
||||||
|
|
||||||
|
**Requisiti coperti** — REQ-… con il testo essenziale e il tipo (P/C/N).
|
||||||
|
|
||||||
|
**Regole normative** — punti elenco presi dalla spec, con i «non» in evidenza.
|
||||||
|
|
||||||
|
**Contratto**
|
||||||
|
- API: `METODO /percorso` → ingresso, uscita, esiti/codici (openapi.yaml:riga)
|
||||||
|
- Dati: tabelle/colonne/vincoli toccati (DATABASE.md §n)
|
||||||
|
- Stati: transizioni ammesse (DOMAIN_WORKFLOW.md §n)
|
||||||
|
|
||||||
|
**Criteri di accettazione → test**
|
||||||
|
| Criterio | Test previsto | Stato attuale (TRACEABILITY) |
|
||||||
|
|---|---|---|
|
||||||
|
| D1 | … | ✅ / 🟡 / ⬜ |
|
||||||
|
|
||||||
|
**Piano** — passi in ordine, file di codice probabilmente toccati.
|
||||||
|
|
||||||
|
**Incoerenze trovate** — documento A dice X, documento B dice Y; fonte di verità scelta e perché.
|
||||||
|
Se nessuna: «nessuna rilevata».
|
||||||
|
|
||||||
|
**Domande per l'utente** — solo quelle che bloccano.
|
||||||
|
```
|
||||||
|
|
||||||
|
<sub>STS Lab Srl · Spec-Driven Reader</sub>
|
||||||
@@ -0,0 +1,48 @@
|
|||||||
|
# Chiusura del ciclo — STS Lab Srl
|
||||||
|
|
||||||
|
Checklist da seguire a lavoro finito, **nella stessa modifica del codice**. Ogni voce è
|
||||||
|
condizionale: aggiorna solo ciò che il lavoro ha davvero toccato.
|
||||||
|
|
||||||
|
## 1. Verifica prima di scrivere «fatto»
|
||||||
|
|
||||||
|
- [ ] I test dei criteri di accettazione del task esistono e sono stati **eseguiti**.
|
||||||
|
- [ ] Annotato il conteggio reale della suite (es. «backend 614 (+3), tutti passanti»).
|
||||||
|
- [ ] Se una verifica è stata fatta solo con test e non contro il sistema reale, scriverlo.
|
||||||
|
- [ ] Se qualcosa non è verificabile ora (cluster, casella reale, fornitore esterno), aprire
|
||||||
|
un task `T-xxx` per la verifica mancante invece di dichiarare ✅.
|
||||||
|
|
||||||
|
## 2. Documenti di tracciamento
|
||||||
|
|
||||||
|
- [ ] **TODO** — stato del task; nuovi task con l'ID successivo libero, la spec e lo stato.
|
||||||
|
Data «Ultimo aggiornamento» (e «precedente», se il file la usa).
|
||||||
|
- [ ] **TRACEABILITY** — righe REQ interessate: criteri coperti e stato. ✅ solo con test passanti.
|
||||||
|
Aggiornare anche la riga di copertura dell'area.
|
||||||
|
- [ ] **Spec** — se la regola è cambiata o estesa: nuova sezione `§n.bis`, nuovi criteri
|
||||||
|
(lettera della spec + numero successivo), nuovi task nella tabella *Task*.
|
||||||
|
- [ ] **REQUIREMENTS** — nuovo `REQ-<AREA>-<nn>` se nasce un comportamento nuovo; tipo N
|
||||||
|
con la `D-xxx` d'origine; nuovo `DIF-nn` se è emerso un difetto.
|
||||||
|
|
||||||
|
## 3. Decisioni e memoria
|
||||||
|
|
||||||
|
- [ ] **DECISIONS** — una `D-xxx` nuova per ogni scelta strutturale, deviazione da una spec o
|
||||||
|
cambio di un requisito di parità. Formato: Contesto → Decisione → Alternative valutate →
|
||||||
|
Conseguenze. Aggiungerla anche alla tabella indice. Se sostituisce una decisione,
|
||||||
|
marcare la vecchia «Superata da D-xxx» senza cancellarne il testo.
|
||||||
|
- [ ] **DEVELOPMENT_LOG** — voce in testa (ordine cronologico inverso): `## AAAA-MM-GG (n) · titolo`.
|
||||||
|
Cosa si è scoperto, cosa è stato tentato e respinto e **perché**, misure reali.
|
||||||
|
- [ ] **PROJECT_MEMORY** — solo se è emerso un vincolo che, dimenticato, farebbe ripetere un errore.
|
||||||
|
|
||||||
|
## 4. Comunicazione
|
||||||
|
|
||||||
|
- [ ] **CHANGELOG** — sezione *[Non rilasciato]*; linguaggio per l'utente del prodotto
|
||||||
|
(Aggiunto / Modificato / Corretto), non dettagli interni.
|
||||||
|
- [ ] **00-INDEX** — riquadro in testa `> **Titolo (AAAA-MM-GG):** …` con gli ID coinvolti
|
||||||
|
(`REQ-…`, `D-…`, `T-…`) e il conteggio dei test; aggiornare la data dell'indice e la
|
||||||
|
riga della spec nella mappa se ne cambia lo stato o il numero di criteri.
|
||||||
|
|
||||||
|
## 5. Coerenza finale
|
||||||
|
|
||||||
|
- [ ] Rieseguire `spec_index.py overview <docs>`: nessun nuovo ID «citato ma mai definito».
|
||||||
|
- [ ] Nessun segreto, password o chiave nei documenti aggiornati.
|
||||||
|
|
||||||
|
<sub>STS Lab Srl · Spec-Driven Reader</sub>
|
||||||
@@ -0,0 +1,91 @@
|
|||||||
|
# Layout della documentazione — STS Lab Srl
|
||||||
|
|
||||||
|
Due forme ricorrenti nei progetti STS Lab Srl. La skill deve funzionare con entrambe e con
|
||||||
|
varianti intermedie. Per un progetto nuovo l'utente sceglie quale creare: i modelli sono in
|
||||||
|
`templates/strutturato/` e `templates/piatto/` (vedi [scrittura.md](scrittura.md)).
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## A. Layout strutturato (es. `KadeonCad_v2/docs`)
|
||||||
|
|
||||||
|
```
|
||||||
|
docs/
|
||||||
|
├── 00-INDEX.md mappa, stato degli step, novità recenti in riquadri datati
|
||||||
|
├── 01-product/ COSA e PER CHI
|
||||||
|
│ ├── VISION.md perché esiste, perimetro, non-obiettivi
|
||||||
|
│ ├── GLOSSARY.md lessico condiviso (usare gli stessi termini nel codice)
|
||||||
|
│ ├── PERSONAS_CASI_USO.md attori e casi d'uso end-to-end
|
||||||
|
│ └── REQUIREMENTS.md REQ-<AREA>-<nn> + DIF-<nn> (difetti noti)
|
||||||
|
├── 02-architecture/ COME È FATTO
|
||||||
|
│ ├── ARCHITECTURE.md · C4_MODEL.md · DOMAIN_WORKFLOW.md (macchina a stati, invarianti)
|
||||||
|
│ ├── DATA_MODEL.md (entità, relazioni, invarianti) · SECURITY.md · STORAGE.md
|
||||||
|
│ └── <componente>.md (AI_GATEWAY, MESH_ENGINE, …)
|
||||||
|
├── 03-specs/ CONTRATTO PER L'IMPLEMENTAZIONE
|
||||||
|
│ └── SPEC-<nnn>-<slug>.md
|
||||||
|
├── 04-api/ CONTRATTO ESTERNO
|
||||||
|
│ ├── openapi.yaml FONTE DI VERITÀ dell'API
|
||||||
|
│ └── API.md · WEBHOOKS.md · INTEGRATION_*.md
|
||||||
|
├── 05-data/ DATABASE.md (schema fisico) · MIGRATION_*.md · SEED_BOOTSTRAP.md
|
||||||
|
├── 06-devops/ INFRASTRUCTURE · KUBERNETES · CI_CD · ENVIRONMENTS · OBSERVABILITY · RUNBOOK · BACKUP_DR
|
||||||
|
├── 07-quality/ TEST_STRATEGY · ACCEPTANCE_CRITERIA · TRACEABILITY · liste di parità
|
||||||
|
└── 08-project/ DECISIONS · ROADMAP · TODO · CHANGELOG · DEVELOPMENT_LOG · PROJECT_MEMORY
|
||||||
|
```
|
||||||
|
|
||||||
|
**Dove cercare cosa**
|
||||||
|
|
||||||
|
| Domanda | Documento |
|
||||||
|
|---|---|
|
||||||
|
| Cosa deve fare il prodotto? | `01-product/REQUIREMENTS.md` |
|
||||||
|
| Come deve farlo questa funzione? | `03-specs/SPEC-xxx` |
|
||||||
|
| Che forma ha la rotta? | `04-api/openapi.yaml` (poi API.md per le convenzioni) |
|
||||||
|
| Che colonne/vincoli ha la tabella? | `05-data/DATABASE.md`; entità logiche in `02-architecture/DATA_MODEL.md` |
|
||||||
|
| Transizioni di stato ammesse? | `02-architecture/DOMAIN_WORKFLOW.md` |
|
||||||
|
| Perché è così? | `08-project/DECISIONS.md` (`## D-xxx`), poi `DEVELOPMENT_LOG.md` |
|
||||||
|
| È fatto? È verificato? | `08-project/TODO.md`, `07-quality/TRACEABILITY.md` |
|
||||||
|
| Come si rilascia / variabili d'ambiente? | `06-devops/ENVIRONMENTS.md`, `KUBERNETES.md` |
|
||||||
|
|
||||||
|
**Legenda stati usata:** ⬜ da scrivere/fare · 🟡 in corso/parziale · ✅ completo/verificato ·
|
||||||
|
🔒 congelato (modifica solo con nuova D-xxx) · ⏸ sospeso.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## B. Layout piatto (es. `Kadeon/kadeon/src/docs`)
|
||||||
|
|
||||||
|
```
|
||||||
|
docs/
|
||||||
|
├── PROJECT_MEMORY.md «leggere sempre prima di scrivere codice»; sintesi architettura,
|
||||||
|
│ decisioni, componenti già creati, sessioni
|
||||||
|
├── ARCHITECTURE.md · API.md · DATABASE.md · AI_GATEWAY.md · OUTPUT_SCHEMA.md
|
||||||
|
├── <MODULO>.md proposta/specifica di un modulo (es. CAD_MODULE.md)
|
||||||
|
├── <area>/DESIGN.md proposte con opzioni e «domande ancora aperte» (es. whatsapp/)
|
||||||
|
├── <area>/openapi.yaml contratto del modulo
|
||||||
|
├── DECISIONS.md D-xxx con Stato · Contesto · Opzioni · Scelta · Motivazione
|
||||||
|
├── TODO.md T-<lettera><nn> raggruppati per tema, con Prio (P0–P3) e Stato
|
||||||
|
├── CHANGELOG.md · DEVELOPMENT_LOG.md
|
||||||
|
```
|
||||||
|
|
||||||
|
Differenze da tenere presenti:
|
||||||
|
|
||||||
|
- Non ci sono `REQ-`/`SPEC-`: il ruolo della spec lo svolge il **documento di modulo** o la
|
||||||
|
sezione di PROJECT_MEMORY/ARCHITECTURE; il cancello §3 si applica a quello.
|
||||||
|
- Gli ID dei task hanno un prefisso tematico (`T-S01` sicurezza, `T-Q5`, `T-H01`…).
|
||||||
|
- Stati in inglese: `pending` · `in_progress` · `done` · `blocked`; decisioni `accepted` ·
|
||||||
|
`proposed` · `superseded`.
|
||||||
|
- Un `DESIGN.md` con «Domande ancora aperte» **non è approvato**: chiarire con l'utente.
|
||||||
|
- PROJECT_MEMORY può essere lungo e datato: confronta la sua data con quelle di TODO e
|
||||||
|
DECISIONS.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## C. Formati degli ID
|
||||||
|
|
||||||
|
| ID | Forma | Dove nasce | Note |
|
||||||
|
|---|---|---|---|
|
||||||
|
| Requisito | `REQ-<AREA>-<nn>` (AREA 2–5 lettere) | REQUIREMENTS | Tipo **P/C/N**; mai rinumerato |
|
||||||
|
| Difetto | `DIF-<nn>` | REQUIREMENTS (sezione difetti) | ogni DIF ha un REQ di tipo C e un test |
|
||||||
|
| Specifica | `SPEC-<nnn>` | file `03-specs/SPEC-nnn-slug.md` | riga `Stato:` in testa |
|
||||||
|
| Task | `T-<nnn>` o `T-<lettera><nn>`, suffissi `b`, `c` | sezione *Task* della spec e TODO | barrato se chiuso senza lavoro |
|
||||||
|
| Decisione | `D-<nnn>` | DECISIONS | *superata*, mai cancellata |
|
||||||
|
| Criterio | lettera + numero (`D1`, `P12`, `M18`) | sezione *Criteri* della spec | ⚠ `D1` criterio ≠ `D-001` decisione |
|
||||||
|
|
||||||
|
<sub>STS Lab Srl · Spec-Driven Reader</sub>
|
||||||
@@ -0,0 +1,181 @@
|
|||||||
|
# Scrivere la documentazione spec-driven — STS Lab Srl
|
||||||
|
|
||||||
|
Guida per creare la documentazione quando il progetto non ce l'ha, completarla quando è solo
|
||||||
|
uno scheletro, o aggiungere una spec a un progetto che già la usa.
|
||||||
|
|
||||||
|
`S` = `python ~/.claude/skills/sts-spec-driven/scripts/spec_index.py`
|
||||||
|
(da PowerShell: `python $HOME\.claude\skills\sts-spec-driven\scripts\spec_index.py`)
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 0. Scegliere il layout — lo decide l'utente
|
||||||
|
|
||||||
|
Chiedi sempre con `AskUserQuestion`, prima di creare file. Proponi come primo, con
|
||||||
|
«(Consigliato)», il layout che si adatta al progetto:
|
||||||
|
|
||||||
|
| Layout | Quando consigliarlo | Cosa crea |
|
||||||
|
|---|---|---|
|
||||||
|
| **Strutturato** | più moduli o servizi, integrazioni con altri sistemi, riscrittura di un sistema esistente, più persone al lavoro, committente esterno, requisiti contrattuali | `00-INDEX` + `01-product … 08-project`, 29 documenti, spec in `03-specs/SPEC-nnn-*.md` |
|
||||||
|
| **Piatto** | progetto piccolo o prototipo, un solo modulo, un solo sviluppatore, tempi brevi | 8 documenti nella stessa cartella, una spec per modulo `<NOME>_MODULE.md` |
|
||||||
|
|
||||||
|
Chiedi nella stessa domanda (o subito dopo) **dove** creare la cartella: default `docs/` nella
|
||||||
|
radice del repository (decisione D-003 dei modelli). Se esiste già una cartella con documenti
|
||||||
|
sparsi, non sovrascriverla: proponi di crearci dentro lo scheletro e di spostare i contenuti
|
||||||
|
esistenti nei documenti giusti.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 1. Creare lo scheletro
|
||||||
|
|
||||||
|
```bash
|
||||||
|
S scaffold <repo>/docs --layout strutturato --progetto "Nome Progetto"
|
||||||
|
S scaffold <repo>/docs --layout piatto --progetto "Nome Progetto"
|
||||||
|
```
|
||||||
|
|
||||||
|
Lo script **non sovrascrive mai** un file esistente (li elenca come «già esistenti»). I
|
||||||
|
documenti nascono con segnaposto `<!-- DA COMPILARE: … -->` che spiegano cosa scrivere, e con
|
||||||
|
le decisioni iniziali già pronte: `D-001` stack (Proposta), `D-002` metodo spec-driven,
|
||||||
|
`D-003` documentazione nel repository.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 2. Raccogliere le informazioni
|
||||||
|
|
||||||
|
### 2.1 Prima guarda, poi chiedi
|
||||||
|
|
||||||
|
Prima di fare domande leggi ciò che esiste: `README`, `CLAUDE.md`, manifest delle dipendenze
|
||||||
|
(`package.json`, `pyproject.toml`, `composer.json`, …), `docker-compose`, cartelle di codice,
|
||||||
|
documenti del committente forniti dall'utente. Non chiedere ciò che puoi ricavare.
|
||||||
|
|
||||||
|
### 2.2 Intervista — al massimo 4 domande per giro, solo ciò che manca
|
||||||
|
|
||||||
|
| Tema | Domande |
|
||||||
|
|---|---|
|
||||||
|
| Problema | Chi usa il prodotto? Cosa fa oggi senza? Quanto costa il problema (tempo, errori)? |
|
||||||
|
| Perimetro | Cosa deve esserci nel primo rilascio? Cosa è esplicitamente fuori? |
|
||||||
|
| Vincoli | Stack imposto? Sistemi esistenti da integrare o da sostituire? Scadenze? |
|
||||||
|
| Utenti | Quali ruoli? Chi può fare cosa? Multi-azienda (tenant)? |
|
||||||
|
| Dati | Quali dati personali o sensibili? Per quanto si conservano? |
|
||||||
|
| Esercizio | Dove gira (cloud, on-premise, Kubernetes)? Quali ambienti? |
|
||||||
|
| Successo | Come si misura che il progetto ha funzionato? |
|
||||||
|
|
||||||
|
Le risposte vanno nei documenti, non solo nella conversazione.
|
||||||
|
|
||||||
|
### 2.3 Progetto con codice ma senza documentazione
|
||||||
|
|
||||||
|
Ricostruisci dal codice, come è stato fatto in KadeonCad_v2:
|
||||||
|
|
||||||
|
- ogni comportamento osservato diventa un `REQ` di tipo **P** (parità) con *Origine*
|
||||||
|
`file:funzione`; il codice è la fonte di verità, non i commenti;
|
||||||
|
- ogni difetto visto leggendo diventa un `DIF-nn` + un `REQ` di tipo **C**;
|
||||||
|
- ogni scelta tecnica già fatta diventa una `D-xxx` *Accettata* con la data di oggi e
|
||||||
|
«ricostruita dal codice» nel contesto;
|
||||||
|
- le spec delle parti già scritte nascono comunque *da approvare*: l'utente conferma che il
|
||||||
|
comportamento attuale è quello voluto.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 3. Ordine di scrittura
|
||||||
|
|
||||||
|
Ogni step termina con un **riepilogo all'utente** e la sua conferma prima del successivo.
|
||||||
|
A fine step aggiorna lo stato nella tabella degli step di `00-INDEX` (⬜ → 🟡 → ✅).
|
||||||
|
|
||||||
|
### Layout strutturato
|
||||||
|
|
||||||
|
| Step | Documenti | Esce quando |
|
||||||
|
|:-:|---|---|
|
||||||
|
| 0 | `00-INDEX` (cos'è, obiettivi, struttura del repo), `D-001` stack, `PROJECT_MEMORY` §1 | l'utente conferma obiettivi e stack |
|
||||||
|
| 1 | `VISION` → `GLOSSARY` → `PERSONAS_CASI_USO` → `REQUIREMENTS` → `ARCHITECTURE`, `C4_MODEL`, `DOMAIN_WORKFLOW`, `DATA_MODEL`, `SECURITY` | requisiti rivisti dall'utente |
|
||||||
|
| 2 | una `SPEC` per capability (`S new-spec`) | ogni REQ è coperto da almeno una spec |
|
||||||
|
| 3 | `openapi.yaml` + `API.md`, `DATABASE.md`, `SEED_BOOTSTRAP.md` | ogni rotta delle spec è nel contratto |
|
||||||
|
| 4 | `06-devops/*` | ambienti e pipeline descritti |
|
||||||
|
| 5 | `TEST_STRATEGY`, `ACCEPTANCE_CRITERIA`, `TRACEABILITY`, `ROADMAP`, `TODO` | `S check` senza ID orfani né requisiti scoperti |
|
||||||
|
|
||||||
|
Per un progetto piccolo in layout strutturato gli step 4 e parte del 5 possono restare
|
||||||
|
⬜ con una riga «rimandato a …» nell'indice: meglio dichiarato vuoto che riempito di generico.
|
||||||
|
|
||||||
|
### Layout piatto
|
||||||
|
|
||||||
|
1. `PROJECT_MEMORY` §1–2 e `ARCHITECTURE`.
|
||||||
|
2. `DECISIONS` (`D-001` stack).
|
||||||
|
3. Primo documento di modulo: `S new-spec <docs> --titolo "…" --prefisso X`.
|
||||||
|
4. `API.md`, `DATABASE.md` per ciò che il modulo tocca.
|
||||||
|
5. `TODO` con la lettera del modulo e i suoi task.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 4. Regole di qualità
|
||||||
|
|
||||||
|
### Requisiti
|
||||||
|
- Un comportamento per riga, osservabile e verificabile; «il sistema …».
|
||||||
|
- Numeri espliciti al posto di aggettivi («entro 5 s», «≥ 200 pezzi», non «veloce», «grande»).
|
||||||
|
- Niente soluzioni tecniche nel requisito (quelle vanno nella spec o in una `D-xxx`).
|
||||||
|
- Ogni requisito ha Tipo (P/C/N) e Origine. Aree di 2–5 lettere maiuscole (`AUT`, `ING`, `NFR`).
|
||||||
|
|
||||||
|
### Specifiche
|
||||||
|
- Forma **normativa**: «il sistema rifiuta…», «non ricalcola…». I «non» in grassetto.
|
||||||
|
- Algoritmi in pseudocodice; combinazioni di casi in tabella.
|
||||||
|
- Contratto API con la **tabella degli esiti** e i codici HTTP; poi subito in `openapi.yaml`.
|
||||||
|
- Criteri di accettazione binari, nella forma «Dato …, quando …, allora …»; ogni requisito
|
||||||
|
coperto ha almeno un criterio; i casi limite (valore 199/200, assente, altro tenant) sono
|
||||||
|
criteri a sé.
|
||||||
|
- Task piccoli (indicativamente ≤ 1 giorno), con dipendenze; l'ultimo è sempre «Test di
|
||||||
|
accettazione <lettera>1–<lettera>n».
|
||||||
|
- Numerazione: `SPEC-nnn` → task `T-nnn0…T-nnn9`, criteri con la lettera della spec
|
||||||
|
(SPEC-001 → A, SPEC-002 → B, …). Usa `S next-id` per non sbagliare.
|
||||||
|
- Documento di modulo (layout piatto): la sezione «Domande ancora aperte» deve essere vuota o
|
||||||
|
«nessuna» prima dell'approvazione.
|
||||||
|
|
||||||
|
### Decisioni
|
||||||
|
- Alternative **reali** valutate, con il motivo dello scarto.
|
||||||
|
- Conseguenze comprese quelle negative (costi, limiti accettati).
|
||||||
|
|
||||||
|
### Sempre
|
||||||
|
- **Non inventare.** Ciò che non sai resta `DA COMPILARE` o diventa una domanda all'utente;
|
||||||
|
mai numeri, nomi di sistemi o vincoli plausibili ma non confermati.
|
||||||
|
- **Mai approvare da solo.** Le spec nascono «da approvare»; diventano «Approvata» solo dopo
|
||||||
|
un sì esplicito dell'utente (§5).
|
||||||
|
- Italiano, frasi brevi, niente linguaggio promozionale. Gli stessi termini del `GLOSSARY`.
|
||||||
|
- Nessun segreto nei documenti: solo il nome della variabile che lo contiene.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 5. Approvare una spec (solo su richiesta dell'utente)
|
||||||
|
|
||||||
|
1. Riga di stato: `Stato: **Approvata** · Versione 1.0 · AAAA-MM-GG`.
|
||||||
|
2. `00-INDEX` §03: riga della spec con numero di criteri, blocco di task, stato ✅.
|
||||||
|
3. `TODO`: i task della spec nella fase giusta, stato ⬜.
|
||||||
|
4. `TRACEABILITY`: una riga per requisito coperto (REQ → SPEC §n → T → criteri → ⬜).
|
||||||
|
5. `DEVELOPMENT_LOG`: voce breve con cosa è stato deciso approvando.
|
||||||
|
6. `S check <docs>`.
|
||||||
|
|
||||||
|
Una spec approvata si modifica solo con una nuova `D-xxx` o con una revisione tracciata
|
||||||
|
(versione 1.1, sezione `§n.bis`).
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 6. Aggiungere una spec a un progetto che già esiste
|
||||||
|
|
||||||
|
```bash
|
||||||
|
S next-id <docs> SPEC # numero libero
|
||||||
|
S new-spec <docs> --titolo "Portale cliente" # crea SPEC-nnn-portale-cliente.md, da approvare
|
||||||
|
S next-id <docs> REQ --area POR # se servono requisiti nuovi
|
||||||
|
S next-id <docs> D # se la spec nasce da una decisione
|
||||||
|
```
|
||||||
|
|
||||||
|
Poi: requisiti nuovi in `REQUIREMENTS` (tipo N, origine `D-xxx`), riga nella mappa di
|
||||||
|
`00-INDEX`, riquadro «novità» in testa all'indice, e la procedura del §5 quando l'utente approva.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 7. Verifica finale
|
||||||
|
|
||||||
|
```bash
|
||||||
|
S check <docs>
|
||||||
|
```
|
||||||
|
|
||||||
|
Prima di consegnare: nessun ID orfano, nessun requisito scoperto, nessun task delle spec
|
||||||
|
assente dal TODO. I segnaposto «DA COMPILARE» rimasti devono corrispondere solo a parti
|
||||||
|
dichiarate rimandate. Riporta all'utente l'esito del controllo, non solo «fatto».
|
||||||
|
|
||||||
|
<sub>STS Lab Srl · Spec-Driven Reader</sub>
|
||||||
@@ -0,0 +1,669 @@
|
|||||||
|
#!/usr/bin/env python3
|
||||||
|
"""
|
||||||
|
STS Lab Srl — Spec-Driven Reader · spec_index.py
|
||||||
|
Copyright (c) 2026 STS Lab Srl. Tutti i diritti riservati.
|
||||||
|
|
||||||
|
Strumento della skill «sts-spec-driven» per leggere e scrivere documentazione spec-driven.
|
||||||
|
|
||||||
|
Lettura (non scrive nulla):
|
||||||
|
overview <docs> Che forma ha la documentazione? Quali spec, in che stato?
|
||||||
|
find <docs> <ID> Dove è definito un ID e chi lo cita? (REQ-, SPEC-, T-, D-, DIF-)
|
||||||
|
context <docs> <ID> Definizione, ID collegati a un passo, righe di TODO e TRACEABILITY.
|
||||||
|
check <docs> Coerenza: ID orfani, spec senza criteri/task, task fuori dal TODO,
|
||||||
|
spec non approvate con lavoro già fatto, segnaposto da compilare.
|
||||||
|
next-id <docs> <TIPO> Prossimo ID libero: REQ (con --area), SPEC, D, DIF, T (con --spec
|
||||||
|
o --prefisso).
|
||||||
|
|
||||||
|
Scrittura (non sovrascrive mai un file esistente):
|
||||||
|
scaffold <docs> --layout strutturato|piatto --progetto NOME
|
||||||
|
Crea lo scheletro della documentazione dai modelli.
|
||||||
|
new-spec <docs> --titolo "…" Crea una nuova spec (strutturato: 03-specs/SPEC-nnn-slug.md;
|
||||||
|
piatto: <NOME>_MODULE.md, serve --prefisso).
|
||||||
|
|
||||||
|
Solo libreria standard Python 3.8+.
|
||||||
|
"""
|
||||||
|
from __future__ import annotations
|
||||||
|
|
||||||
|
import argparse
|
||||||
|
import datetime as dt
|
||||||
|
import re
|
||||||
|
import shutil
|
||||||
|
import sys
|
||||||
|
import unicodedata
|
||||||
|
from collections import defaultdict
|
||||||
|
from pathlib import Path
|
||||||
|
|
||||||
|
BRAND = "STS Lab Srl · Spec-Driven Reader"
|
||||||
|
SKILL_DIR = Path(__file__).resolve().parent.parent
|
||||||
|
TEMPLATES = SKILL_DIR / "templates"
|
||||||
|
LAYOUTS = ("strutturato", "piatto")
|
||||||
|
|
||||||
|
ID_RE = re.compile(
|
||||||
|
r"(?<![A-Za-z0-9_-])("
|
||||||
|
r"REQ-[A-Z]{2,5}-\d{1,3}[a-z]?"
|
||||||
|
r"|SPEC-\d{3}"
|
||||||
|
r"|DIF-\d{1,3}"
|
||||||
|
r"|D-\d{3}"
|
||||||
|
r"|T-[A-Z]{0,2}\d{1,4}[a-z]?"
|
||||||
|
r")(?![A-Za-z0-9_])"
|
||||||
|
)
|
||||||
|
|
||||||
|
KEY_DOCS = [
|
||||||
|
"00-INDEX.md", "INDEX.md", "README.md",
|
||||||
|
"PROJECT_MEMORY.md", "REQUIREMENTS.md", "DECISIONS.md", "TODO.md",
|
||||||
|
"TRACEABILITY.md", "ARCHITECTURE.md", "API.md", "openapi.yaml",
|
||||||
|
"DATABASE.md", "DATA_MODEL.md", "CHANGELOG.md", "DEVELOPMENT_LOG.md", "ROADMAP.md",
|
||||||
|
"GLOSSARY.md", "ACCEPTANCE_CRITERIA.md", "TEST_STRATEGY.md",
|
||||||
|
]
|
||||||
|
PLACEHOLDER = "DA COMPILARE"
|
||||||
|
|
||||||
|
|
||||||
|
def out(text: str = "") -> None:
|
||||||
|
print(text)
|
||||||
|
|
||||||
|
|
||||||
|
# ---------------------------------------------------------------- caricamento
|
||||||
|
|
||||||
|
def load(docs: Path) -> dict[Path, list[str]]:
|
||||||
|
files: dict[Path, list[str]] = {}
|
||||||
|
for p in sorted(docs.rglob("*")):
|
||||||
|
if p.is_file() and p.suffix.lower() in {".md", ".yaml", ".yml"}:
|
||||||
|
try:
|
||||||
|
files[p] = p.read_text(encoding="utf-8-sig", errors="replace").splitlines()
|
||||||
|
except OSError:
|
||||||
|
continue
|
||||||
|
return files
|
||||||
|
|
||||||
|
|
||||||
|
def strip_comments(lines: list[str]) -> list[str]:
|
||||||
|
"""Svuota i commenti HTML (<!-- … -->, anche su più righe) mantenendo i numeri di riga:
|
||||||
|
i segnaposto dei modelli non devono contare come ID."""
|
||||||
|
res, inside = [], False
|
||||||
|
for line in lines:
|
||||||
|
buf, i = "", 0
|
||||||
|
while i < len(line):
|
||||||
|
if inside:
|
||||||
|
j = line.find("-->", i)
|
||||||
|
if j < 0:
|
||||||
|
i = len(line)
|
||||||
|
else:
|
||||||
|
inside, i = False, j + 3
|
||||||
|
else:
|
||||||
|
j = line.find("<!--", i)
|
||||||
|
if j < 0:
|
||||||
|
buf += line[i:]
|
||||||
|
i = len(line)
|
||||||
|
else:
|
||||||
|
buf += line[i:j]
|
||||||
|
inside, i = True, j + 4
|
||||||
|
res.append(buf)
|
||||||
|
return res
|
||||||
|
|
||||||
|
|
||||||
|
def rel(p: Path, docs: Path) -> str:
|
||||||
|
return p.relative_to(docs).as_posix()
|
||||||
|
|
||||||
|
|
||||||
|
def kind(id_: str) -> str:
|
||||||
|
for prefix in ("REQ", "SPEC", "DIF"):
|
||||||
|
if id_.startswith(prefix + "-"):
|
||||||
|
return prefix
|
||||||
|
return id_.split("-")[0]
|
||||||
|
|
||||||
|
|
||||||
|
def is_definition(line: str, id_: str, path: Path) -> bool:
|
||||||
|
"""Una riga *definisce* l'ID se è un titolo che inizia con l'ID o una riga di
|
||||||
|
tabella il cui primo campo è l'ID (anche in **grassetto** o ~~barrato~~)."""
|
||||||
|
s = line.strip()
|
||||||
|
if s.startswith("#"):
|
||||||
|
# solo titoli Markdown che *iniziano* con l'ID ("## D-014 — …", "# SPEC-004 — …")
|
||||||
|
return path.suffix.lower() == ".md" and re.match(r"#+\s+\**" + re.escape(id_) + r"(?![0-9A-Za-z])", s) is not None
|
||||||
|
if s.startswith("|"):
|
||||||
|
first = s.strip("|").split("|")[0]
|
||||||
|
first = re.sub(r"[*~`\[\]]", "", first).strip()
|
||||||
|
# [D-001](#ancora) -> "D-001(#ancora)" : prendiamo il primo token
|
||||||
|
first = re.split(r"[\s(]", first)[0] if first else first
|
||||||
|
return first == id_
|
||||||
|
return False
|
||||||
|
|
||||||
|
|
||||||
|
def scan(files: dict[Path, list[str]], docs: Path):
|
||||||
|
defs: dict[str, list[tuple[str, int, str]]] = defaultdict(list)
|
||||||
|
refs: dict[str, list[tuple[str, int, str]]] = defaultdict(list)
|
||||||
|
for p, raw in files.items():
|
||||||
|
r = rel(p, docs)
|
||||||
|
lines = strip_comments(raw) if p.suffix.lower() == ".md" else raw
|
||||||
|
m = re.match(r"(SPEC-\d{3})", p.name)
|
||||||
|
if m:
|
||||||
|
defs[m.group(1)].append((r, 1, raw[0] if raw else p.name))
|
||||||
|
for n, line in enumerate(lines, 1):
|
||||||
|
for id_ in set(ID_RE.findall(line)):
|
||||||
|
if is_definition(line, id_, p):
|
||||||
|
defs[id_].append((r, n, line.strip()))
|
||||||
|
else:
|
||||||
|
refs[id_].append((r, n, line.strip()))
|
||||||
|
return defs, refs
|
||||||
|
|
||||||
|
|
||||||
|
def detect_layout(docs: Path, files: dict[Path, list[str]] | None = None) -> str:
|
||||||
|
if any(d.is_dir() and re.match(r"\d{2}-", d.name) for d in docs.iterdir()):
|
||||||
|
return "strutturato"
|
||||||
|
if (docs / "03-specs").exists() or any(re.match(r"SPEC-\d{3}", p.name) for p in (files or {})):
|
||||||
|
return "strutturato"
|
||||||
|
return "piatto"
|
||||||
|
|
||||||
|
|
||||||
|
def spec_status(lines: list[str]) -> str:
|
||||||
|
for line in lines[:12]:
|
||||||
|
m = re.match(r"\s*Stato\s*:\s*(.+)", line)
|
||||||
|
if m:
|
||||||
|
return re.sub(r"[*`]", "", m.group(1)).strip()
|
||||||
|
return "— (riga «Stato:» assente)"
|
||||||
|
|
||||||
|
|
||||||
|
def index_status(files: dict[Path, list[str]], spec_id: str) -> str:
|
||||||
|
"""Ripiego: lo stato della spec letto dalla sua riga nell'indice (ultima cella)."""
|
||||||
|
for p, lines in files.items():
|
||||||
|
if p.name in ("00-INDEX.md", "INDEX.md", "README.md"):
|
||||||
|
for line in strip_comments(lines):
|
||||||
|
if line.lstrip().startswith("|") and spec_id in line:
|
||||||
|
cells = [c.strip() for c in line.strip().strip("|").split("|")]
|
||||||
|
if cells:
|
||||||
|
return "dall'indice: " + re.sub(r"[*`]", "", cells[-1])
|
||||||
|
return ""
|
||||||
|
|
||||||
|
|
||||||
|
def status_flag(st: str) -> str:
|
||||||
|
if re.search(r"da approvare|bozza|proposta|proposed|draft", st, re.I):
|
||||||
|
return " <-- NON approvata: non implementare"
|
||||||
|
if re.search(r"approvat|✅|accettat|accepted", st, re.I):
|
||||||
|
return ""
|
||||||
|
return " <-- stato incerto: verificare prima di implementare"
|
||||||
|
|
||||||
|
|
||||||
|
def is_approved(st: str) -> bool:
|
||||||
|
return status_flag(st) == ""
|
||||||
|
|
||||||
|
|
||||||
|
def last_update(lines: list[str]) -> str:
|
||||||
|
for line in lines[:12]:
|
||||||
|
m = re.search(r"Ultimo aggiornamento\s*:\s*\**([0-9]{4}-[0-9]{2}-[0-9]{2})", line)
|
||||||
|
if m:
|
||||||
|
return m.group(1)
|
||||||
|
return ""
|
||||||
|
|
||||||
|
|
||||||
|
def spec_docs(files: dict[Path, list[str]], layout: str) -> list[Path]:
|
||||||
|
"""Spec del layout strutturato (SPEC-nnn-*.md) o documenti di modulo del layout piatto
|
||||||
|
(qualunque .md non chiave con una riga «Stato:» in testa)."""
|
||||||
|
res = []
|
||||||
|
for p, lines in files.items():
|
||||||
|
if p.suffix.lower() != ".md":
|
||||||
|
continue
|
||||||
|
if re.match(r"SPEC-\d{3}", p.name):
|
||||||
|
res.append(p)
|
||||||
|
elif layout == "piatto" and p.name not in KEY_DOCS and any(re.match(r"\s*Stato\s*:", l) for l in lines[:12]):
|
||||||
|
res.append(p)
|
||||||
|
return sorted(res)
|
||||||
|
|
||||||
|
|
||||||
|
RANGE_RE = re.compile(r"REQ-([A-Z]{2,5})-(\d{1,3})`?\s*(?:…|\.\.\.|–)\s*`?(?:REQ-[A-Z]{2,5}-)?(\d{1,3})")
|
||||||
|
SHORT_RE = re.compile(r"(?<![A-Za-z0-9-])([A-Z]{2,5})-(\d{2,3})(?![0-9])")
|
||||||
|
|
||||||
|
|
||||||
|
def covered_reqs(spec_texts: list[str], trace_lines: list[str]) -> set[str]:
|
||||||
|
"""Requisiti coperti: citati in una spec (anche come intervallo «REQ-X-01 … 05») o su una
|
||||||
|
riga di TRACEABILITY che nomina una spec (anche in forma breve «PRI-04»)."""
|
||||||
|
cov: set[str] = set()
|
||||||
|
for t in spec_texts:
|
||||||
|
cov |= {i for i in ID_RE.findall(t) if kind(i) == "REQ"}
|
||||||
|
for area, a, b in RANGE_RE.findall(t):
|
||||||
|
cov |= {"REQ-%s-%02d" % (area, k) for k in range(int(a), int(b) + 1)}
|
||||||
|
for line in trace_lines:
|
||||||
|
if "SPEC-" in line:
|
||||||
|
cov |= {i for i in ID_RE.findall(line) if kind(i) == "REQ"}
|
||||||
|
cov |= {"REQ-%s-%s" % (a, n) for a, n in SHORT_RE.findall(line)
|
||||||
|
if a not in ("SPEC", "REQ", "DIF")}
|
||||||
|
return cov
|
||||||
|
|
||||||
|
|
||||||
|
# ---------------------------------------------------------------- lettura
|
||||||
|
|
||||||
|
def cmd_overview(docs: Path) -> None:
|
||||||
|
files = load(docs)
|
||||||
|
defs, refs = scan(files, docs)
|
||||||
|
out(f"== {BRAND} ==")
|
||||||
|
out(f"Cartella : {docs}")
|
||||||
|
out(f"Layout : {detect_layout(docs, files)}")
|
||||||
|
out(f"File : {len(files)} (md/yaml)")
|
||||||
|
out()
|
||||||
|
out("-- Documenti chiave (ordine di lettura consigliato) --")
|
||||||
|
by_name = defaultdict(list)
|
||||||
|
for p in files:
|
||||||
|
by_name[p.name].append(p)
|
||||||
|
for name in KEY_DOCS:
|
||||||
|
for p in by_name.get(name, []):
|
||||||
|
lines = files[p]
|
||||||
|
upd = last_update(lines)
|
||||||
|
out(f" {rel(p, docs):45s} {len(lines):6d} righe {('agg. ' + upd) if upd else ''}")
|
||||||
|
big = [(p, len(l)) for p, l in files.items() if len(l) > 800]
|
||||||
|
if big:
|
||||||
|
out()
|
||||||
|
out("-- File grandi: NON leggerli interi, cerca la sezione per ID/data --")
|
||||||
|
for p, n in sorted(big, key=lambda x: -x[1]):
|
||||||
|
out(f" {rel(p, docs):45s} {n:6d} righe")
|
||||||
|
specs = spec_docs(files, detect_layout(docs, files))
|
||||||
|
if specs:
|
||||||
|
out()
|
||||||
|
out("-- Specifiche / documenti di modulo --")
|
||||||
|
for p in specs:
|
||||||
|
st = spec_status(files[p])
|
||||||
|
if st.startswith("—"):
|
||||||
|
st = index_status(files, p.stem[:8]) or st
|
||||||
|
out(f" {rel(p, docs):45s} {st}{status_flag(st)}")
|
||||||
|
todo = [(p, sum(PLACEHOLDER in l for l in ls)) for p, ls in files.items()]
|
||||||
|
todo = [(p, n) for p, n in todo if n]
|
||||||
|
if todo:
|
||||||
|
out()
|
||||||
|
out(f"-- Segnaposto «{PLACEHOLDER}» ancora presenti ({sum(n for _, n in todo)}) --")
|
||||||
|
for p, n in sorted(todo, key=lambda x: rel(x[0], docs)):
|
||||||
|
out(f" {rel(p, docs):45s} {n:4d}")
|
||||||
|
out()
|
||||||
|
out("-- ID trovati (definiti / citati) --")
|
||||||
|
counts = defaultdict(lambda: [0, 0])
|
||||||
|
for id_ in set(defs) | set(refs):
|
||||||
|
k = kind(id_)
|
||||||
|
counts[k][0] += 1 if id_ in defs else 0
|
||||||
|
counts[k][1] += 1
|
||||||
|
for k in ("REQ", "SPEC", "T", "D", "DIF"):
|
||||||
|
if k in counts:
|
||||||
|
out(f" {k:5s} {counts[k][0]:5d} definiti su {counts[k][1]:5d} distinti")
|
||||||
|
orphans = sorted(i for i in refs if i not in defs and kind(i) in {"REQ", "SPEC", "D"})
|
||||||
|
if orphans:
|
||||||
|
out()
|
||||||
|
out(f"-- Citati ma mai definiti ({len(orphans)}) — possibile deriva della documentazione --")
|
||||||
|
out(" " + ", ".join(orphans[:60]) + (" …" if len(orphans) > 60 else ""))
|
||||||
|
|
||||||
|
|
||||||
|
def cmd_find(docs: Path, id_: str, limit: int) -> None:
|
||||||
|
files = load(docs)
|
||||||
|
defs, refs = scan(files, docs)
|
||||||
|
out(f"== {BRAND} · {id_} ==")
|
||||||
|
if not defs.get(id_):
|
||||||
|
out("Definizione: NON TROVATA (ID inesistente, rinumerato o definito con formato insolito)")
|
||||||
|
else:
|
||||||
|
out("Definizione:")
|
||||||
|
for r, n, line in defs[id_]:
|
||||||
|
out(f" {r}:{n} {line[:220]}")
|
||||||
|
rs = refs.get(id_, [])
|
||||||
|
out(f"Citazioni: {len(rs)}")
|
||||||
|
by_file = defaultdict(list)
|
||||||
|
for r, n, line in rs:
|
||||||
|
by_file[r].append((n, line))
|
||||||
|
for r, items in sorted(by_file.items(), key=lambda x: -len(x[1])):
|
||||||
|
out(f" {r} ({len(items)})")
|
||||||
|
for n, line in items[:limit]:
|
||||||
|
out(f" :{n} {line[:180]}")
|
||||||
|
if len(items) > limit:
|
||||||
|
out(f" … altre {len(items) - limit}")
|
||||||
|
|
||||||
|
|
||||||
|
def section(lines: list[str], start: int, max_lines: int = 60) -> list[str]:
|
||||||
|
"""Dal titolo alla riga 'start' (1-based) fino al prossimo titolo di pari o superiore livello."""
|
||||||
|
head = lines[start - 1]
|
||||||
|
if not head.lstrip().startswith("#"):
|
||||||
|
return [head]
|
||||||
|
level = len(head) - len(head.lstrip("#"))
|
||||||
|
body = [head]
|
||||||
|
for line in lines[start:]:
|
||||||
|
s = line.lstrip()
|
||||||
|
if s.startswith("#") and (len(s) - len(s.lstrip("#"))) <= level:
|
||||||
|
break
|
||||||
|
body.append(line)
|
||||||
|
if len(body) >= max_lines:
|
||||||
|
body.append("… (sezione troncata: aprire il file per il resto)")
|
||||||
|
break
|
||||||
|
return body
|
||||||
|
|
||||||
|
|
||||||
|
def cmd_context(docs: Path, id_: str) -> None:
|
||||||
|
files = load(docs)
|
||||||
|
defs, refs = scan(files, docs)
|
||||||
|
by_rel = {rel(p, docs): l for p, l in files.items()}
|
||||||
|
out(f"== {BRAND} · contesto di {id_} ==")
|
||||||
|
|
||||||
|
if id_.startswith("SPEC-"):
|
||||||
|
spec_file = next((p for p in files if p.name.startswith(id_)), None)
|
||||||
|
if spec_file is None:
|
||||||
|
out("Spec non trovata.")
|
||||||
|
return
|
||||||
|
lines = files[spec_file]
|
||||||
|
out(f"File : {rel(spec_file, docs)} ({len(lines)} righe)")
|
||||||
|
out(f"Stato : {spec_status(lines)}")
|
||||||
|
out()
|
||||||
|
out("Indice delle sezioni:")
|
||||||
|
for n, line in enumerate(lines, 1):
|
||||||
|
if line.startswith("## ") or line.startswith("### "):
|
||||||
|
out(f" :{n} {line}")
|
||||||
|
linked = sorted({i for line in strip_comments(lines) for i in ID_RE.findall(line)} - {id_})
|
||||||
|
else:
|
||||||
|
linked = set()
|
||||||
|
for r, n, line in defs.get(id_, []):
|
||||||
|
out(f"Definizione: {r}:{n}")
|
||||||
|
body = section(by_rel[r], n) if line.startswith("#") else [line]
|
||||||
|
for b in body:
|
||||||
|
out(" " + b)
|
||||||
|
for b in strip_comments(body):
|
||||||
|
linked |= set(ID_RE.findall(b))
|
||||||
|
if not defs.get(id_):
|
||||||
|
out("Definizione: NON TROVATA")
|
||||||
|
for r, n, line in refs.get(id_, []):
|
||||||
|
if "SPEC-" in Path(r).name:
|
||||||
|
linked.add(Path(r).name[:8])
|
||||||
|
linked = sorted(linked - {id_})
|
||||||
|
|
||||||
|
out()
|
||||||
|
out("ID collegati (un passo):")
|
||||||
|
groups = defaultdict(list)
|
||||||
|
for i in linked:
|
||||||
|
groups[kind(i)].append(i)
|
||||||
|
for k in ("REQ", "SPEC", "T", "D", "DIF"):
|
||||||
|
if groups.get(k):
|
||||||
|
out(f" {k:5s} " + ", ".join(groups[k]))
|
||||||
|
|
||||||
|
out()
|
||||||
|
out("Definizioni sintetiche dei collegati (righe di tabella / titoli):")
|
||||||
|
for i in linked:
|
||||||
|
for r, n, line in defs.get(i, [])[:1]:
|
||||||
|
out(f" [{i}] {r}:{n} {line[:200]}")
|
||||||
|
|
||||||
|
for target in ("TODO.md", "TRACEABILITY.md"):
|
||||||
|
hits = [(r, n, l) for r, n, l in refs.get(id_, []) + defs.get(id_, []) if Path(r).name == target]
|
||||||
|
if hits:
|
||||||
|
out()
|
||||||
|
out(f"Righe in {target}:")
|
||||||
|
for r, n, line in hits[:25]:
|
||||||
|
out(f" {r}:{n} {line[:220]}")
|
||||||
|
|
||||||
|
|
||||||
|
def cmd_check(docs: Path) -> int:
|
||||||
|
files = load(docs)
|
||||||
|
defs, refs = scan(files, docs)
|
||||||
|
issues: list[tuple[str, str]] = []
|
||||||
|
|
||||||
|
for i in sorted(refs):
|
||||||
|
if i not in defs and kind(i) in {"REQ", "SPEC", "D", "DIF"}:
|
||||||
|
issues.append(("ID orfano", f"{i} è citato ma non definito (es. {refs[i][0][0]}:{refs[i][0][1]})"))
|
||||||
|
|
||||||
|
specs = spec_docs(files, detect_layout(docs, files))
|
||||||
|
spec_text = {p: "\n".join(strip_comments(files[p])) for p in specs}
|
||||||
|
for p, text in spec_text.items():
|
||||||
|
r = rel(p, docs)
|
||||||
|
if not re.search(r"^#{2,3}\s.*criteri", text, re.I | re.M):
|
||||||
|
issues.append(("Spec incompleta", f"{r}: manca la sezione «Criteri di accettazione»"))
|
||||||
|
if not re.search(r"^#{2,3}\s.*task", text, re.I | re.M):
|
||||||
|
issues.append(("Spec incompleta", f"{r}: manca la sezione «Task»"))
|
||||||
|
if re.search(r"^#{2,3}\s.*domande ancora aperte", text, re.I | re.M):
|
||||||
|
tail = text.split("omande ancora aperte", 1)[1]
|
||||||
|
body = [l for l in tail.splitlines()[1:] if l.strip() and not l.startswith("#")]
|
||||||
|
if body and not re.search(r"nessuna", " ".join(body), re.I):
|
||||||
|
issues.append(("Spec non approvabile", f"{r}: «Domande ancora aperte» non vuota"))
|
||||||
|
|
||||||
|
trace = [l for p, ls in files.items() if p.name == "TRACEABILITY.md" for l in strip_comments(ls)]
|
||||||
|
req_in_specs = covered_reqs(list(spec_text.values()), trace)
|
||||||
|
req_defined = {i for i in defs if kind(i) == "REQ"}
|
||||||
|
for i in sorted(req_defined - req_in_specs):
|
||||||
|
if specs:
|
||||||
|
issues.append(("Requisito scoperto", f"{i} non è coperto da nessuna spec"))
|
||||||
|
|
||||||
|
todo_files = [p for p in files if p.name == "TODO.md"]
|
||||||
|
todo_text = "\n".join("\n".join(strip_comments(files[p])) for p in todo_files)
|
||||||
|
if todo_files:
|
||||||
|
for p, text in spec_text.items():
|
||||||
|
for t in sorted({i for i in ID_RE.findall(text) if kind(i) == "T"}):
|
||||||
|
if any(d[0] == rel(p, docs) for d in defs.get(t, [])) and t not in todo_text:
|
||||||
|
issues.append(("Task fuori dal TODO", f"{t} definito in {rel(p, docs)} ma assente dal TODO"))
|
||||||
|
|
||||||
|
for p in specs:
|
||||||
|
st = spec_status(files[p])
|
||||||
|
if st.startswith("—"):
|
||||||
|
st = index_status(files, p.stem[:8]) or st
|
||||||
|
if is_approved(st):
|
||||||
|
continue
|
||||||
|
tasks = {i for i in ID_RE.findall(spec_text[p]) if kind(i) == "T"}
|
||||||
|
done = []
|
||||||
|
for line in todo_text.splitlines():
|
||||||
|
ids = set(ID_RE.findall(line))
|
||||||
|
if ids & tasks and re.search(r"✅|\bdone\b", line):
|
||||||
|
done.extend(sorted(ids & tasks))
|
||||||
|
if done:
|
||||||
|
issues.append(("Deriva di stato", f"{rel(p, docs)} è «{st}» ma ha task fatti: {', '.join(sorted(set(done))[:8])}"))
|
||||||
|
|
||||||
|
ph = [(rel(p, docs), sum(PLACEHOLDER in l for l in ls)) for p, ls in files.items()]
|
||||||
|
for r, n in sorted(ph):
|
||||||
|
if n:
|
||||||
|
issues.append(("Da compilare", f"{r}: {n} segnaposto «{PLACEHOLDER}»"))
|
||||||
|
|
||||||
|
out(f"== {BRAND} · controllo di coerenza ==")
|
||||||
|
out(f"Cartella: {docs}")
|
||||||
|
if not issues:
|
||||||
|
out("Nessun problema rilevato.")
|
||||||
|
return 0
|
||||||
|
by_kind = defaultdict(list)
|
||||||
|
for k, msg in issues:
|
||||||
|
by_kind[k].append(msg)
|
||||||
|
for k in ("ID orfano", "Requisito scoperto", "Spec incompleta", "Spec non approvabile",
|
||||||
|
"Task fuori dal TODO", "Deriva di stato", "Da compilare"):
|
||||||
|
if by_kind.get(k):
|
||||||
|
out()
|
||||||
|
out(f"-- {k} ({len(by_kind[k])}) --")
|
||||||
|
for msg in by_kind[k][:40]:
|
||||||
|
out(" " + msg)
|
||||||
|
if len(by_kind[k]) > 40:
|
||||||
|
out(f" … altri {len(by_kind[k]) - 40}")
|
||||||
|
return 1
|
||||||
|
|
||||||
|
|
||||||
|
# ---------------------------------------------------------------- numerazione
|
||||||
|
|
||||||
|
def _max_num(ids, pattern: str) -> int:
|
||||||
|
nums = [int(m.group(1)) for i in ids for m in [re.fullmatch(pattern, i)] if m]
|
||||||
|
return max(nums, default=0)
|
||||||
|
|
||||||
|
|
||||||
|
def next_id(docs: Path, tipo: str, area: str | None = None, spec: str | None = None,
|
||||||
|
prefisso: str | None = None) -> str:
|
||||||
|
files = load(docs) if docs.exists() else {}
|
||||||
|
defs, refs = scan(files, docs) if files else ({}, {})
|
||||||
|
known = set(defs) | set(refs)
|
||||||
|
for p in files:
|
||||||
|
m = re.match(r"(SPEC-\d{3})", p.name)
|
||||||
|
if m:
|
||||||
|
known.add(m.group(1))
|
||||||
|
tipo = tipo.upper()
|
||||||
|
if tipo == "SPEC":
|
||||||
|
return "SPEC-%03d" % (_max_num(known, r"SPEC-(\d{3})") + 1)
|
||||||
|
if tipo == "D":
|
||||||
|
return "D-%03d" % (_max_num(known, r"D-(\d{3})") + 1)
|
||||||
|
if tipo == "DIF":
|
||||||
|
return "DIF-%02d" % (_max_num(known, r"DIF-(\d{1,3})") + 1)
|
||||||
|
if tipo == "REQ":
|
||||||
|
if not area:
|
||||||
|
raise SystemExit("next-id REQ richiede --area (es. --area AUT)")
|
||||||
|
a = area.upper()
|
||||||
|
return "REQ-%s-%02d" % (a, _max_num(known, r"REQ-" + a + r"-(\d{1,3})") + 1)
|
||||||
|
if tipo == "T":
|
||||||
|
if prefisso:
|
||||||
|
pf = prefisso.upper()
|
||||||
|
return "T-%s%02d" % (pf, _max_num(known, r"T-" + pf + r"(\d{1,4})") + 1)
|
||||||
|
if spec:
|
||||||
|
n = int(re.sub(r"\D", "", spec))
|
||||||
|
block = [i for i in known if re.fullmatch(r"T-\d{3}", i) and int(i[2:]) // 10 == n]
|
||||||
|
if not block:
|
||||||
|
return f"T-{n * 10:03d}"
|
||||||
|
last = max(int(i[2:]) for i in block)
|
||||||
|
if last % 10 < 9:
|
||||||
|
return f"T-{last + 1:03d}"
|
||||||
|
sfx = [i for i in known if re.fullmatch("T-%03d[b-z]" % last, i)]
|
||||||
|
return f"T-{last:03d}{chr(ord(max(sfx)[-1]) + 1) if sfx else 'b'}"
|
||||||
|
return "T-%03d" % (_max_num(known, r"T-(\d{3})") + 1)
|
||||||
|
raise SystemExit(f"Tipo sconosciuto: {tipo} (REQ, SPEC, T, D, DIF)")
|
||||||
|
|
||||||
|
|
||||||
|
# ---------------------------------------------------------------- scrittura
|
||||||
|
|
||||||
|
def fill(text: str, values: dict[str, str]) -> str:
|
||||||
|
for k, v in values.items():
|
||||||
|
text = text.replace("{{" + k + "}}", v)
|
||||||
|
return text
|
||||||
|
|
||||||
|
|
||||||
|
def slugify(s: str) -> str:
|
||||||
|
s = unicodedata.normalize("NFKD", s).encode("ascii", "ignore").decode()
|
||||||
|
return re.sub(r"[^a-z0-9]+", "-", s.lower()).strip("-")
|
||||||
|
|
||||||
|
|
||||||
|
def cmd_scaffold(docs: Path, layout: str, progetto: str, data: str) -> int:
|
||||||
|
src = TEMPLATES / layout
|
||||||
|
if not src.is_dir():
|
||||||
|
raise SystemExit(f"Modelli non trovati: {src}")
|
||||||
|
created, skipped = [], []
|
||||||
|
for t in sorted(src.rglob("*")):
|
||||||
|
if t.is_dir():
|
||||||
|
continue
|
||||||
|
dest = docs / t.relative_to(src)
|
||||||
|
if dest.exists():
|
||||||
|
skipped.append(dest)
|
||||||
|
continue
|
||||||
|
dest.parent.mkdir(parents=True, exist_ok=True)
|
||||||
|
text = t.read_text(encoding="utf-8")
|
||||||
|
dest.write_text(fill(text, {"PROGETTO": progetto, "DATA": data}), encoding="utf-8")
|
||||||
|
created.append(dest)
|
||||||
|
if layout == "strutturato":
|
||||||
|
(docs / "03-specs").mkdir(parents=True, exist_ok=True)
|
||||||
|
out(f"== {BRAND} · scaffold «{layout}» ==")
|
||||||
|
out(f"Cartella: {docs}")
|
||||||
|
out(f"Creati : {len(created)}")
|
||||||
|
for p in created:
|
||||||
|
out(f" + {rel(p, docs)}")
|
||||||
|
if skipped:
|
||||||
|
out(f"Già esistenti, NON toccati: {len(skipped)}")
|
||||||
|
for p in skipped:
|
||||||
|
out(f" = {rel(p, docs)}")
|
||||||
|
out()
|
||||||
|
out("Prossimo passo: compilare i segnaposto «DA COMPILARE» seguendo references/scrittura.md,")
|
||||||
|
out("poi `check` per verificare la coerenza.")
|
||||||
|
return 0
|
||||||
|
|
||||||
|
|
||||||
|
def criterion_letter(n: int) -> str:
|
||||||
|
return chr(64 + n) if 1 <= n <= 26 else f"S{n}"
|
||||||
|
|
||||||
|
|
||||||
|
def cmd_new_spec(docs: Path, titolo: str, data: str, slug: str | None, prefisso: str | None,
|
||||||
|
layout: str | None) -> int:
|
||||||
|
files = load(docs) if docs.exists() else {}
|
||||||
|
layout = layout or detect_layout(docs, files)
|
||||||
|
if layout == "strutturato":
|
||||||
|
sid = next_id(docs, "SPEC")
|
||||||
|
n = int(sid[5:])
|
||||||
|
slug = slug or slugify(titolo)
|
||||||
|
dest = docs / "03-specs" / f"{sid}-{slug}.md"
|
||||||
|
values = {"SPEC_ID": sid, "TITOLO": titolo, "DATA": data,
|
||||||
|
"LETTERA": criterion_letter(n),
|
||||||
|
"T0": f"T-{n * 10:03d}", "T1": f"T-{n * 10 + 1:03d}"}
|
||||||
|
tpl = TEMPLATES / "spec.md"
|
||||||
|
else:
|
||||||
|
if not prefisso:
|
||||||
|
raise SystemExit("Nel layout piatto serve --prefisso (lettera dei task del modulo, es. W)")
|
||||||
|
pf = prefisso.upper()
|
||||||
|
used = {i for p, ls in files.items() for l in strip_comments(ls) for i in ID_RE.findall(l)
|
||||||
|
if re.fullmatch(r"T-" + pf + r"\d+[a-z]?", i)}
|
||||||
|
if used:
|
||||||
|
raise SystemExit(f"Il prefisso T-{pf} è già usato ({', '.join(sorted(used)[:5])}): sceglierne un altro.")
|
||||||
|
name = (slug or slugify(titolo)).upper().replace("-", "_")
|
||||||
|
if not name.endswith("_MODULE"):
|
||||||
|
name += "_MODULE"
|
||||||
|
dest = docs / f"{name}.md"
|
||||||
|
values = {"TITOLO": titolo, "DATA": data, "PREFISSO": pf}
|
||||||
|
tpl = TEMPLATES / "modulo.md"
|
||||||
|
if dest.exists():
|
||||||
|
raise SystemExit(f"Esiste già: {dest} — non lo sovrascrivo.")
|
||||||
|
dest.parent.mkdir(parents=True, exist_ok=True)
|
||||||
|
dest.write_text(fill(tpl.read_text(encoding="utf-8"), values), encoding="utf-8")
|
||||||
|
out(f"== {BRAND} · nuova spec ==")
|
||||||
|
out(f"Creata: {dest}")
|
||||||
|
out("Stato : da approvare")
|
||||||
|
if layout == "strutturato":
|
||||||
|
out(f"Task : blocco {values['T0']}…T-{n * 10 + 9:03d} · criteri {values['LETTERA']}1…")
|
||||||
|
out("Ricorda: riga nella mappa di 00-INDEX §03, task in TODO, righe in TRACEABILITY.")
|
||||||
|
else:
|
||||||
|
out("Ricorda: riga in PROJECT_MEMORY §4, lettera del modulo e task in TODO.")
|
||||||
|
return 0
|
||||||
|
|
||||||
|
|
||||||
|
# ---------------------------------------------------------------- main
|
||||||
|
|
||||||
|
def main() -> int:
|
||||||
|
try:
|
||||||
|
sys.stdout.reconfigure(encoding="utf-8")
|
||||||
|
sys.stderr.reconfigure(encoding="utf-8")
|
||||||
|
except Exception:
|
||||||
|
pass
|
||||||
|
today = dt.date.today().isoformat()
|
||||||
|
ap = argparse.ArgumentParser(description=f"{BRAND} — documentazione spec-driven")
|
||||||
|
sub = ap.add_subparsers(dest="cmd", required=True)
|
||||||
|
o = sub.add_parser("overview")
|
||||||
|
o.add_argument("docs")
|
||||||
|
f = sub.add_parser("find")
|
||||||
|
f.add_argument("docs")
|
||||||
|
f.add_argument("id")
|
||||||
|
f.add_argument("--limit", type=int, default=8)
|
||||||
|
c = sub.add_parser("context")
|
||||||
|
c.add_argument("docs")
|
||||||
|
c.add_argument("id")
|
||||||
|
k = sub.add_parser("check")
|
||||||
|
k.add_argument("docs")
|
||||||
|
n = sub.add_parser("next-id")
|
||||||
|
n.add_argument("docs")
|
||||||
|
n.add_argument("tipo", help="REQ | SPEC | T | D | DIF")
|
||||||
|
n.add_argument("--area")
|
||||||
|
n.add_argument("--spec")
|
||||||
|
n.add_argument("--prefisso")
|
||||||
|
s = sub.add_parser("scaffold")
|
||||||
|
s.add_argument("docs")
|
||||||
|
s.add_argument("--layout", choices=LAYOUTS, required=True)
|
||||||
|
s.add_argument("--progetto", required=True)
|
||||||
|
s.add_argument("--data", default=today)
|
||||||
|
ns = sub.add_parser("new-spec")
|
||||||
|
ns.add_argument("docs")
|
||||||
|
ns.add_argument("--titolo", required=True)
|
||||||
|
ns.add_argument("--slug")
|
||||||
|
ns.add_argument("--prefisso", help="solo layout piatto: lettera dei task del modulo")
|
||||||
|
ns.add_argument("--layout", choices=LAYOUTS)
|
||||||
|
ns.add_argument("--data", default=today)
|
||||||
|
a = ap.parse_args()
|
||||||
|
docs = Path(a.docs).resolve()
|
||||||
|
|
||||||
|
if a.cmd == "scaffold":
|
||||||
|
return cmd_scaffold(docs, a.layout, a.progetto, a.data)
|
||||||
|
if a.cmd == "new-spec":
|
||||||
|
return cmd_new_spec(docs, a.titolo, a.data, a.slug, a.prefisso, a.layout)
|
||||||
|
if not docs.is_dir():
|
||||||
|
print(f"Cartella non trovata: {docs}", file=sys.stderr)
|
||||||
|
return 2
|
||||||
|
if a.cmd == "overview":
|
||||||
|
cmd_overview(docs)
|
||||||
|
elif a.cmd == "find":
|
||||||
|
cmd_find(docs, a.id, a.limit)
|
||||||
|
elif a.cmd == "context":
|
||||||
|
cmd_context(docs, a.id)
|
||||||
|
elif a.cmd == "check":
|
||||||
|
return cmd_check(docs)
|
||||||
|
elif a.cmd == "next-id":
|
||||||
|
out(next_id(docs, a.tipo, a.area, a.spec, a.prefisso))
|
||||||
|
return 0
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
sys.exit(main())
|
||||||
@@ -0,0 +1,60 @@
|
|||||||
|
# {{TITOLO}}
|
||||||
|
|
||||||
|
Stato: **da approvare** · Versione 0.1 · {{DATA}} · Prefisso task: **T-{{PREFISSO}}**
|
||||||
|
|
||||||
|
**Decisioni di riferimento:** <!-- `D-…` o «nessuna» -->
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 1. Contesto e requisito
|
||||||
|
|
||||||
|
<!-- DA COMPILARE: perché serve, chi lo ha chiesto e quando, cosa deve ottenere l'utente. -->
|
||||||
|
|
||||||
|
## 2. Requisiti
|
||||||
|
|
||||||
|
| ID | Requisito | Origine |
|
||||||
|
|---|---|---|
|
||||||
|
| <!-- REQ-AREA-01 --> | <!-- «Il sistema …», limiti numerici espliciti --> | <!-- committente, data --> |
|
||||||
|
|
||||||
|
## 3. Opzioni valutate e raccomandazione
|
||||||
|
|
||||||
|
<!-- Solo se c'è una scelta da fare. Ogni opzione con pro, contro, costo. La scelta finale
|
||||||
|
diventa una D-xxx in DECISIONS.md. -->
|
||||||
|
|
||||||
|
## 4. Regole
|
||||||
|
|
||||||
|
<!-- DA COMPILARE in forma normativa. -->
|
||||||
|
|
||||||
|
## 5. Architettura del modulo
|
||||||
|
|
||||||
|
<!-- DA COMPILARE: servizi, code, modelli dati, storage toccati. -->
|
||||||
|
|
||||||
|
## 6. Contratto API
|
||||||
|
|
||||||
|
| Metodo | Percorso | Ruolo minimo | Esiti |
|
||||||
|
|---|---|---|---|
|
||||||
|
| <!-- DA COMPILARE --> | | | 200 · 404 · 422 |
|
||||||
|
|
||||||
|
## 7. Errori e casi limite
|
||||||
|
|
||||||
|
| Caso | Comportamento |
|
||||||
|
|---|---|
|
||||||
|
| <!-- DA COMPILARE --> | |
|
||||||
|
|
||||||
|
## 8. Criteri di accettazione
|
||||||
|
|
||||||
|
| # | Criterio |
|
||||||
|
|:-:|---|
|
||||||
|
| {{PREFISSO}}1 | <!-- «Dato …, quando …, allora …» --> |
|
||||||
|
|
||||||
|
## 9. Task
|
||||||
|
|
||||||
|
| ID | Attività | Prio | Dipende da |
|
||||||
|
|----|----------|------|------------|
|
||||||
|
| T-{{PREFISSO}}01 | <!-- DA COMPILARE --> | P1 | — |
|
||||||
|
|
||||||
|
## 10. Domande ancora aperte
|
||||||
|
|
||||||
|
<!-- Finché questa sezione non è vuota il documento non può essere approvato. -->
|
||||||
|
|
||||||
|
- <!-- DA COMPILARE o «nessuna» -->
|
||||||
@@ -0,0 +1,30 @@
|
|||||||
|
# API — {{PROGETTO}}
|
||||||
|
|
||||||
|
Ultimo aggiornamento: **{{DATA}}**
|
||||||
|
|
||||||
|
Il contratto si scrive **prima** del codice. Se esiste un `openapi.yaml`, quello è la fonte di verità.
|
||||||
|
|
||||||
|
## Convenzioni
|
||||||
|
|
||||||
|
| Aspetto | Regola |
|
||||||
|
|---|---|
|
||||||
|
| Prefisso | `/api/v1` |
|
||||||
|
| Formato | JSON, UTF-8, date ISO 8601 UTC |
|
||||||
|
| Autenticazione | <!-- DA COMPILARE --> |
|
||||||
|
| Errori | `{ "error": { "code", "message", "details" } }` |
|
||||||
|
|
||||||
|
## Endpoint — Stato di servizio
|
||||||
|
|
||||||
|
### `GET /health` *(pubblico)*
|
||||||
|
|
||||||
|
Risponde `200 {"status": "ok"}`.
|
||||||
|
|
||||||
|
## Endpoint previsti
|
||||||
|
|
||||||
|
<!-- Un gruppo per modulo. Stato nel titolo: *(previsto)* · ✅ *implementato (T-xxx)*. -->
|
||||||
|
|
||||||
|
### <!-- Gruppo --> — *(previsto)*
|
||||||
|
|
||||||
|
| Metodo | Percorso | Ruolo minimo | Descrizione | Task |
|
||||||
|
|---|---|---|---|---|
|
||||||
|
| <!-- DA COMPILARE --> | | | | |
|
||||||
@@ -0,0 +1,45 @@
|
|||||||
|
# ARCHITECTURE — {{PROGETTO}}
|
||||||
|
|
||||||
|
Ultimo aggiornamento: **{{DATA}}**
|
||||||
|
|
||||||
|
## Struttura del repository
|
||||||
|
|
||||||
|
```
|
||||||
|
<!-- DA COMPILARE -->
|
||||||
|
```
|
||||||
|
|
||||||
|
## 1. Vista d'insieme
|
||||||
|
|
||||||
|
```
|
||||||
|
<!-- DA COMPILARE: schema ASCII dei servizi -->
|
||||||
|
```
|
||||||
|
|
||||||
|
## 2. Servizi/componenti
|
||||||
|
|
||||||
|
| Componente | Tecnologia | Responsabilità |
|
||||||
|
|---|---|---|
|
||||||
|
| <!-- DA COMPILARE --> | | |
|
||||||
|
|
||||||
|
## 3. Flusso principale
|
||||||
|
|
||||||
|
<!-- DA COMPILARE: passo per passo, con code e dati scambiati. -->
|
||||||
|
|
||||||
|
## 4. Macchina a stati
|
||||||
|
|
||||||
|
<!-- DA COMPILARE: stati, transizioni ammesse (ogni altra è rifiutata), invarianti — o «non applicabile». -->
|
||||||
|
|
||||||
|
## 5. Code e lavori asincroni
|
||||||
|
|
||||||
|
<!-- DA COMPILARE o «non applicabile». -->
|
||||||
|
|
||||||
|
## 6. Storage
|
||||||
|
|
||||||
|
<!-- DA COMPILARE: database, file/oggetti, convenzioni di nome. -->
|
||||||
|
|
||||||
|
## 7. Sicurezza e multi-tenancy
|
||||||
|
|
||||||
|
<!-- DA COMPILARE: autenticazione, ruoli, isolamento, segreti (mai nel repository). -->
|
||||||
|
|
||||||
|
## 8. Aperto / da decidere
|
||||||
|
|
||||||
|
- <!-- DA COMPILARE -->
|
||||||
@@ -0,0 +1,10 @@
|
|||||||
|
# CHANGELOG — {{PROGETTO}}
|
||||||
|
|
||||||
|
Formato: ogni voce riporta **data · componente · modifica · motivo**. Le voci più recenti in alto.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## {{DATA}} — Avvio della documentazione
|
||||||
|
|
||||||
|
Creata la documentazione di progetto con metodo spec-driven: PROJECT_MEMORY, ARCHITECTURE, API,
|
||||||
|
DATABASE, DECISIONS (D-001…D-003), TODO.
|
||||||
@@ -0,0 +1,18 @@
|
|||||||
|
# DATABASE — {{PROGETTO}}
|
||||||
|
|
||||||
|
Ultimo aggiornamento: **{{DATA}}**
|
||||||
|
|
||||||
|
Motore: <!-- DA COMPILARE --> · Migrazioni: <!-- DA COMPILARE: strumento e numerazione -->
|
||||||
|
|
||||||
|
Regole: date sempre UTC · una migrazione per modifica, mai riscrivere una migrazione applicata ·
|
||||||
|
nessun file binario nel database.
|
||||||
|
|
||||||
|
## A. <!-- Gruppo di tabelle -->
|
||||||
|
|
||||||
|
### `<!-- tabella -->` *(migrazione `0001`)*
|
||||||
|
|
||||||
|
| Colonna | Tipo | Null | Note |
|
||||||
|
|---|---|:-:|---|
|
||||||
|
| `id` | | no | PK |
|
||||||
|
|
||||||
|
Indici: <!-- DA COMPILARE --> · Vincoli: <!-- DA COMPILARE -->
|
||||||
@@ -0,0 +1,28 @@
|
|||||||
|
# DECISIONS — {{PROGETTO}} (Architecture Decision Records)
|
||||||
|
|
||||||
|
Ultimo aggiornamento: **{{DATA}}**
|
||||||
|
|
||||||
|
Formato: ogni decisione ha contesto, opzioni valutate, scelta e motivazione.
|
||||||
|
Stato: `accepted` · `proposed` · `superseded by D-xxx` · `rejected`.
|
||||||
|
Le decisioni non si cancellano: si superano.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## D-001 — Stack tecnologico
|
||||||
|
- **Stato:** proposed
|
||||||
|
- **Contesto:** <!-- DA COMPILARE -->
|
||||||
|
- **Opzioni:** <!-- (a) …; (b) … -->
|
||||||
|
- **Scelta:** <!-- DA COMPILARE -->
|
||||||
|
- **Motivazione:** <!-- DA COMPILARE -->
|
||||||
|
|
||||||
|
## D-002 — Sviluppo spec-driven
|
||||||
|
- **Stato:** accepted
|
||||||
|
- **Contesto:** le regole di business scritte solo nel codice emergono dal debugging invece che dalla specifica.
|
||||||
|
- **Opzioni:** (a) documentazione a valle del codice; (b) documento di modulo approvato prima del codice.
|
||||||
|
- **Scelta:** (b). Nessun codice senza un documento di modulo in stato *Approvato*, con regole, contratto, criteri di accettazione e task.
|
||||||
|
- **Motivazione:** le regole diventano esplicite e verificabili prima di costare un difetto.
|
||||||
|
|
||||||
|
## D-003 — La documentazione vive nel repository
|
||||||
|
- **Stato:** accepted
|
||||||
|
- **Scelta:** `docs/` nel repository del codice, aggiornata nella stessa modifica del codice che la riguarda.
|
||||||
|
- **Motivazione:** documenti e codice non divergono; la revisione del codice è anche revisione dei documenti.
|
||||||
@@ -0,0 +1,12 @@
|
|||||||
|
# DEVELOPMENT_LOG — {{PROGETTO}}
|
||||||
|
|
||||||
|
Diario operativo per sessione: cosa fatto, problemi, perché si è deciso così, prossime azioni.
|
||||||
|
Le voci più recenti in alto. Le voci non si cancellano.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## {{DATA}} — Avvio della documentazione
|
||||||
|
|
||||||
|
Creato lo scheletro della documentazione spec-driven.
|
||||||
|
|
||||||
|
**Prossime azioni:** completare D-001 (stack), scrivere il primo documento di modulo.
|
||||||
@@ -0,0 +1,68 @@
|
|||||||
|
# PROJECT_MEMORY — {{PROGETTO}}
|
||||||
|
|
||||||
|
> Memoria permanente del progetto. Leggere **sempre** questo file (e l'intera cartella `docs/`)
|
||||||
|
> prima di scrivere codice. Aggiornarlo dopo ogni modifica significativa.
|
||||||
|
|
||||||
|
Ultimo aggiornamento: **{{DATA}}** · Sessione: **avvio della documentazione**
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 1. Cos'è {{PROGETTO}}
|
||||||
|
|
||||||
|
<!-- DA COMPILARE: cosa fa, per chi, flusso ad alto livello in 4-6 passi, valore. -->
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 2. Architettura attuale (sintesi)
|
||||||
|
|
||||||
|
> Dettaglio completo in [`ARCHITECTURE.md`](./ARCHITECTURE.md).
|
||||||
|
|
||||||
|
- <!-- DA COMPILARE: un punto per servizio/componente, con la tecnologia -->
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 3. Decisioni tecniche prese
|
||||||
|
|
||||||
|
> Registro completo con alternative e motivazioni in [`DECISIONS.md`](./DECISIONS.md).
|
||||||
|
|
||||||
|
- D-001 Stack tecnologico *(proposed)*
|
||||||
|
- D-002 Sviluppo spec-driven: nessun codice senza un documento di modulo approvato
|
||||||
|
- D-003 La documentazione vive nel repository e si aggiorna con il codice
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 4. Moduli e documenti di specifica
|
||||||
|
|
||||||
|
| Modulo | Documento | Stato |
|
||||||
|
|---|---|---|
|
||||||
|
| <!-- DA COMPILARE --> | <!-- [`NOME_MODULE.md`](./NOME_MODULE.md) --> | da approvare |
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 5. Componenti GIÀ creati
|
||||||
|
|
||||||
|
- [ ] <!-- DA COMPILARE -->
|
||||||
|
|
||||||
|
## 6. Componenti ANCORA da creare
|
||||||
|
|
||||||
|
- [ ] <!-- DA COMPILARE -->
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 7. Vincoli importanti
|
||||||
|
|
||||||
|
<!-- Ciò che, se dimenticato, fa ripetere un errore. Ogni vincolo con il suo perché. -->
|
||||||
|
|
||||||
|
- <!-- DA COMPILARE -->
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 8. Come continuare (per la prossima sessione)
|
||||||
|
|
||||||
|
1. Leggere questo file, poi [`TODO.md`](./TODO.md) (P0 aperti per primi).
|
||||||
|
2. Per il task scelto, leggere il documento di modulo e le decisioni citate.
|
||||||
|
3. A fine lavoro: TODO, CHANGELOG, DEVELOPMENT_LOG e questo file.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
<sub>Documentazione redatta con il metodo spec-driven di STS Lab Srl.</sub>
|
||||||
@@ -0,0 +1,25 @@
|
|||||||
|
# TODO — {{PROGETTO}}
|
||||||
|
|
||||||
|
Ultimo aggiornamento: **{{DATA}}**
|
||||||
|
|
||||||
|
Legenda stato: `pending` · `in_progress` · `done` · `blocked`
|
||||||
|
Priorità: **P0** (fondante/bloccante) · **P1** (core) · **P2** (importante) · **P3** (successivo)
|
||||||
|
|
||||||
|
**Regola:** un task entra in lavorazione solo se il suo documento di modulo è approvato (D-002).
|
||||||
|
`done` solo con i test del criterio passanti.
|
||||||
|
|
||||||
|
**Numerazione:** `T-<lettera del modulo><nn>` (es. `T-S<nn>` per la sicurezza, `T-W<nn>` per WhatsApp);
|
||||||
|
la lettera si fissa quando nasce il modulo e si annota qui sotto.
|
||||||
|
|
||||||
|
| Lettera | Modulo |
|
||||||
|
|:-:|---|
|
||||||
|
| <!-- S --> | <!-- Sicurezza & API --> |
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Documentazione ({{DATA}})
|
||||||
|
|
||||||
|
| ID | Attività | Prio | Stato |
|
||||||
|
|----|----------|------|-------|
|
||||||
|
| T-D01 | Completare PROJECT_MEMORY, ARCHITECTURE, DECISIONS (D-001) | P0 | in_progress |
|
||||||
|
| T-D02 | Primo documento di modulo approvato | P0 | pending |
|
||||||
@@ -0,0 +1,83 @@
|
|||||||
|
# {{SPEC_ID}} — {{TITOLO}}
|
||||||
|
|
||||||
|
Stato: **da approvare** · Versione 0.1 · {{DATA}}
|
||||||
|
|
||||||
|
**Requisiti coperti:** <!-- DA COMPILARE: `REQ-…` -->
|
||||||
|
**Decisioni di riferimento:** <!-- `D-…` o «nessuna» -->
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 1. Contesto e obiettivo
|
||||||
|
|
||||||
|
<!-- DA COMPILARE: perché questa capability esiste, cosa decide per l'utente. Un dato misurato
|
||||||
|
vale più di un aggettivo. Se la spec è a sé per una ragione (regola delicata, rischio), dirlo. -->
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 2. Cosa cambia rispetto a ciò che è già scritto
|
||||||
|
|
||||||
|
<!-- Solo se la spec modifica requisiti, decisioni o altre spec. Altrimenti rimuovere la sezione. -->
|
||||||
|
|
||||||
|
| Dove | Prima | Dopo |
|
||||||
|
|---|---|---|
|
||||||
|
| | | |
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 3. Regole
|
||||||
|
|
||||||
|
<!-- DA COMPILARE in forma NORMATIVA: «il sistema …», «non …», limiti numerici espliciti.
|
||||||
|
Pseudocodice per gli algoritmi. Una tabella per le combinazioni di casi. Quando un comportamento
|
||||||
|
sembra un errore ma è voluto, dirlo: «è una decisione, non una dimenticanza». -->
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 4. Contratto API
|
||||||
|
|
||||||
|
### `METODO /api/v1/percorso`
|
||||||
|
|
||||||
|
**Ingresso:** <!-- campi e tipi -->
|
||||||
|
|
||||||
|
**Uscita:** <!-- campi e tipi -->
|
||||||
|
|
||||||
|
| Esito | Codice |
|
||||||
|
|---|:-:|
|
||||||
|
| <!-- Riuscito --> | 200 |
|
||||||
|
| <!-- Non trovato o di altro tenant --> | 404 |
|
||||||
|
| <!-- Validazione fallita --> | 422 |
|
||||||
|
|
||||||
|
Il dettaglio formale va in `04-api/openapi.yaml` **prima** del codice.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 5. Dati
|
||||||
|
|
||||||
|
<!-- DA COMPILARE: entità, colonne, vincoli toccati — rimando a DATA_MODEL e DATABASE. -->
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 6. Errori e casi limite
|
||||||
|
|
||||||
|
| Caso | Comportamento |
|
||||||
|
|---|---|
|
||||||
|
| <!-- DA COMPILARE --> | |
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 7. Criteri di accettazione
|
||||||
|
|
||||||
|
Ogni criterio è verificabile da un test e ha un esito binario.
|
||||||
|
|
||||||
|
| # | Criterio |
|
||||||
|
|:-:|---|
|
||||||
|
| {{LETTERA}}1 | <!-- DA COMPILARE: «Dato …, quando …, allora …» --> |
|
||||||
|
| {{LETTERA}}2 | |
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 8. Task
|
||||||
|
|
||||||
|
| ID | Task | Dipende da |
|
||||||
|
|---|---|---|
|
||||||
|
| **{{T0}}** | <!-- DA COMPILARE --> | — |
|
||||||
|
| **{{T1}}** | Test di accettazione {{LETTERA}}1–{{LETTERA}}n | {{T0}} |
|
||||||
@@ -0,0 +1,153 @@
|
|||||||
|
# {{PROGETTO}} — Indice della documentazione
|
||||||
|
|
||||||
|
Ultimo aggiornamento: **{{DATA}}**
|
||||||
|
|
||||||
|
| Step | Contenuto | Stato |
|
||||||
|
|:-:|---|:-:|
|
||||||
|
| 0 | Scheletro della documentazione · indice · decisioni iniziali | 🟡 |
|
||||||
|
| 1 | `01-product/` + `02-architecture/` — visione, requisiti, architettura | ⬜ |
|
||||||
|
| 2 | `03-specs/` — specifiche e criteri di accettazione | ⬜ |
|
||||||
|
| 3 | `04-api/` + `05-data/` — contratto OpenAPI e schema dati | ⬜ |
|
||||||
|
| 4 | `06-devops/` — ambienti, pipeline, infrastruttura | ⬜ |
|
||||||
|
| 5 | `07-quality/` + `08-project/` — tracciabilità e backlog | ⬜ |
|
||||||
|
| 6 | Implementazione — vedi [`08-project/ROADMAP.md`](08-project/ROADMAP.md) | ⬜ |
|
||||||
|
|
||||||
|
<!-- Novità: un riquadro per ogni consegna rilevante, il più recente in alto. Esempio:
|
||||||
|
> **Titolo breve (AAAA-MM-GG):** cosa è cambiato e perché — `REQ-…`, `D-…`, `T-…`.
|
||||||
|
> Verificato come (test, sistema reale) — backend N (+k).
|
||||||
|
-->
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Cos'è questo progetto
|
||||||
|
|
||||||
|
<!-- DA COMPILARE: due o tre frasi. Che cosa fa il prodotto, per chi, su quale stack. -->
|
||||||
|
|
||||||
|
Obiettivi vincolanti del progetto:
|
||||||
|
|
||||||
|
1. <!-- DA COMPILARE: obiettivo misurabile -->
|
||||||
|
2. <!-- DA COMPILARE -->
|
||||||
|
3. **Spec-driven** — nessuna riga di codice senza una spec approvata e tracciata (D-002).
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Metodo: spec-driven development
|
||||||
|
|
||||||
|
Il flusso di lavoro è vincolato e va in un'unica direzione:
|
||||||
|
|
||||||
|
```
|
||||||
|
REQ-xxx (01-product/REQUIREMENTS.md)
|
||||||
|
│ cosa deve fare il prodotto
|
||||||
|
▼
|
||||||
|
SPEC-xxx (03-specs/)
|
||||||
|
│ come lo fa: contratto API, dati, regole, errori, criteri di accettazione
|
||||||
|
▼
|
||||||
|
T-xxx (08-project/TODO.md)
|
||||||
|
│ unità di lavoro implementabile
|
||||||
|
▼
|
||||||
|
codice + test
|
||||||
|
│
|
||||||
|
▼
|
||||||
|
07-quality/TRACEABILITY.md ← chiude il cerchio: ogni REQ ha spec, task e test
|
||||||
|
```
|
||||||
|
|
||||||
|
**Regola:** si implementa solo ciò che ha una `SPEC-xxx` in stato *Approvata*. Una spec non
|
||||||
|
approvata non genera task; un task senza spec non entra in lavorazione. Ogni scelta strutturale
|
||||||
|
diventa una decisione numerata `D-xxx` in [`08-project/DECISIONS.md`](08-project/DECISIONS.md).
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Mappa dei documenti
|
||||||
|
|
||||||
|
Legenda stato: ⬜ da scrivere · 🟡 in stesura · ✅ completo · 🔒 congelato (modifica solo via nuova D-xxx)
|
||||||
|
|
||||||
|
### 01 · Prodotto — *cosa* e *per chi*
|
||||||
|
|
||||||
|
| Documento | Contenuto | Stato |
|
||||||
|
|---|---|---|
|
||||||
|
| [`01-product/VISION.md`](01-product/VISION.md) | Perché esiste il prodotto, valore, perimetro, non-obiettivi | ⬜ |
|
||||||
|
| [`01-product/GLOSSARY.md`](01-product/GLOSSARY.md) | Lessico condiviso | ⬜ |
|
||||||
|
| [`01-product/PERSONAS_CASI_USO.md`](01-product/PERSONAS_CASI_USO.md) | Attori, persone, casi d'uso end-to-end | ⬜ |
|
||||||
|
| [`01-product/REQUIREMENTS.md`](01-product/REQUIREMENTS.md) | Requisiti `REQ-*` e difetti noti `DIF-*` | ⬜ |
|
||||||
|
|
||||||
|
### 02 · Architettura — *come è fatto*
|
||||||
|
|
||||||
|
| Documento | Contenuto | Stato |
|
||||||
|
|---|---|---|
|
||||||
|
| [`02-architecture/ARCHITECTURE.md`](02-architecture/ARCHITECTURE.md) | Vista d'insieme, servizi, flusso principale | ⬜ |
|
||||||
|
| [`02-architecture/C4_MODEL.md`](02-architecture/C4_MODEL.md) | Contesto / Contenitori / Componenti | ⬜ |
|
||||||
|
| [`02-architecture/DOMAIN_WORKFLOW.md`](02-architecture/DOMAIN_WORKFLOW.md) | Stati, transizioni ammesse, invarianti | ⬜ |
|
||||||
|
| [`02-architecture/DATA_MODEL.md`](02-architecture/DATA_MODEL.md) | Entità, relazioni, chiavi, cancellazioni, invarianti | ⬜ |
|
||||||
|
| [`02-architecture/SECURITY.md`](02-architecture/SECURITY.md) | Autenticazione, autorizzazione, segreti, audit | ⬜ |
|
||||||
|
|
||||||
|
### 03 · Specifiche — *contratto per l'implementazione*
|
||||||
|
|
||||||
|
| Spec | Capability | Stato |
|
||||||
|
|---|---|---|
|
||||||
|
<!-- Una riga per spec, aggiunta quando la spec nasce:
|
||||||
|
| [`SPEC-001-slug.md`](03-specs/SPEC-001-slug.md) | Capability · N criteri · T-010…019 | 🟡 da approvare |
|
||||||
|
-->
|
||||||
|
|
||||||
|
### 04 · API — *contratto esterno*
|
||||||
|
|
||||||
|
| Documento | Contenuto | Stato |
|
||||||
|
|---|---|---|
|
||||||
|
| [`04-api/API.md`](04-api/API.md) | Catalogo endpoint, convenzioni, errori, paginazione | ⬜ |
|
||||||
|
| [`04-api/openapi.yaml`](04-api/openapi.yaml) | Contratto OpenAPI 3.1 — **fonte di verità** | ⬜ |
|
||||||
|
|
||||||
|
### 05 · Dati
|
||||||
|
|
||||||
|
| Documento | Contenuto | Stato |
|
||||||
|
|---|---|---|
|
||||||
|
| [`05-data/DATABASE.md`](05-data/DATABASE.md) | Schema fisico: tabelle, enumerazioni, indici, vincoli, migrazioni | ⬜ |
|
||||||
|
| [`05-data/SEED_BOOTSTRAP.md`](05-data/SEED_BOOTSTRAP.md) | Stato iniziale, bootstrap idempotente, credenziali | ⬜ |
|
||||||
|
|
||||||
|
### 06 · DevOps
|
||||||
|
|
||||||
|
| Documento | Contenuto | Stato |
|
||||||
|
|---|---|---|
|
||||||
|
| [`06-devops/INFRASTRUCTURE.md`](06-devops/INFRASTRUCTURE.md) | Topologia, servizi, risorse, rete, persistenza | ⬜ |
|
||||||
|
| [`06-devops/ENVIRONMENTS.md`](06-devops/ENVIRONMENTS.md) | dev/qa/prod, variabili, promozione | ⬜ |
|
||||||
|
| [`06-devops/CI_CD.md`](06-devops/CI_CD.md) | Pipeline, verifiche, rilascio, rientro | ⬜ |
|
||||||
|
| [`06-devops/OBSERVABILITY.md`](06-devops/OBSERVABILITY.md) | Log, metriche, allarmi | ⬜ |
|
||||||
|
| [`06-devops/RUNBOOK.md`](06-devops/RUNBOOK.md) | Procedure: sintomo → verifica → azione → conferma | ⬜ |
|
||||||
|
| [`06-devops/BACKUP_DR.md`](06-devops/BACKUP_DR.md) | Backup, ripristino, prova periodica | ⬜ |
|
||||||
|
|
||||||
|
### 07 · Qualità
|
||||||
|
|
||||||
|
| Documento | Contenuto | Stato |
|
||||||
|
|---|---|---|
|
||||||
|
| [`07-quality/TEST_STRATEGY.md`](07-quality/TEST_STRATEGY.md) | Livelli di test, simulatori, criteri di uscita | ⬜ |
|
||||||
|
| [`07-quality/ACCEPTANCE_CRITERIA.md`](07-quality/ACCEPTANCE_CRITERIA.md) | Criteri bloccanti di rilascio | ⬜ |
|
||||||
|
| [`07-quality/TRACEABILITY.md`](07-quality/TRACEABILITY.md) | Matrice REQ → SPEC → T → test, senza righe scoperte | ⬜ |
|
||||||
|
|
||||||
|
### 08 · Progetto
|
||||||
|
|
||||||
|
| Documento | Contenuto | Stato |
|
||||||
|
|---|---|---|
|
||||||
|
| [`08-project/DECISIONS.md`](08-project/DECISIONS.md) | Decisioni architetturali `D-xxx` | 🟡 |
|
||||||
|
| [`08-project/ROADMAP.md`](08-project/ROADMAP.md) | Fasi con criteri di uscita, dipendenze, rischi | ⬜ |
|
||||||
|
| [`08-project/TODO.md`](08-project/TODO.md) | Task `T-xxx` per fase, tracciati sulle spec | ⬜ |
|
||||||
|
| [`08-project/CHANGELOG.md`](08-project/CHANGELOG.md) | Cosa cambia per chi usa il prodotto | ⬜ |
|
||||||
|
| [`08-project/DEVELOPMENT_LOG.md`](08-project/DEVELOPMENT_LOG.md) | Diario tecnico: cosa si è scoperto e perché | ⬜ |
|
||||||
|
| [`08-project/PROJECT_MEMORY.md`](08-project/PROJECT_MEMORY.md) | **Da leggere a inizio di ogni sessione** | 🟡 |
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Struttura del repository
|
||||||
|
|
||||||
|
```
|
||||||
|
<!-- DA COMPILARE: albero delle cartelle principali, una riga di descrizione ciascuna -->
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Riferimenti esterni
|
||||||
|
|
||||||
|
| Risorsa | Percorso / URL |
|
||||||
|
|---|---|
|
||||||
|
| <!-- DA COMPILARE: repository, documenti del committente, sistemi collegati --> | |
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
<sub>Documentazione redatta con il metodo spec-driven di STS Lab Srl.</sub>
|
||||||
@@ -0,0 +1,37 @@
|
|||||||
|
# GLOSSARY — Lessico di {{PROGETTO}}
|
||||||
|
|
||||||
|
Ultimo aggiornamento: **{{DATA}}**
|
||||||
|
|
||||||
|
Un termine, un significato. Gli stessi nomi si usano nei documenti, nel codice (classi,
|
||||||
|
tabelle, rotte) e nell'interfaccia. Se un termine cambia, cambia qui per primo.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 1. Termini di dominio
|
||||||
|
|
||||||
|
| Termine | Significato | Nel codice |
|
||||||
|
|---|---|---|
|
||||||
|
| <!-- DA COMPILARE --> | | `nome_tecnico` |
|
||||||
|
|
||||||
|
## 2. Termini di piattaforma
|
||||||
|
|
||||||
|
| Termine | Significato | Nel codice |
|
||||||
|
|---|---|---|
|
||||||
|
| <!-- DA COMPILARE: es. Tenant, Utente, Ruolo --> | | |
|
||||||
|
|
||||||
|
## 3. Convenzioni di identificazione nei documenti
|
||||||
|
|
||||||
|
| ID | Significato | Dove nasce |
|
||||||
|
|---|---|---|
|
||||||
|
| `REQ-<AREA>-<nn>` | Requisito | `01-product/REQUIREMENTS.md` |
|
||||||
|
| `DIF-<nn>` | Difetto noto | `01-product/REQUIREMENTS.md` |
|
||||||
|
| `SPEC-<nnn>` | Specifica | `03-specs/` |
|
||||||
|
| `T-<nnn>` | Task | sezione *Task* della spec e `08-project/TODO.md` |
|
||||||
|
| `D-<nnn>` | Decisione | `08-project/DECISIONS.md` |
|
||||||
|
| `A1`, `B3`, … | Criterio di accettazione (lettera della spec + numero) | sezione *Criteri* della spec |
|
||||||
|
|
||||||
|
Gli ID sono **immutabili**: non si rinumerano e non si riusano. Un ID chiuso senza lavoro si barra (`~~T-xxx~~`).
|
||||||
|
|
||||||
|
## 4. Falsi amici
|
||||||
|
|
||||||
|
<!-- DA COMPILARE: parole che il committente usa con un significato diverso da quello tecnico. -->
|
||||||
+44
@@ -0,0 +1,44 @@
|
|||||||
|
# PERSONAS E CASI D'USO — {{PROGETTO}}
|
||||||
|
|
||||||
|
Ultimo aggiornamento: **{{DATA}}**
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 1. Attori
|
||||||
|
|
||||||
|
### 1.1 Attori umani
|
||||||
|
|
||||||
|
| Attore | Ruolo nel sistema | Permessi |
|
||||||
|
|---|---|---|
|
||||||
|
| <!-- DA COMPILARE --> | | |
|
||||||
|
|
||||||
|
### 1.2 Attori non umani
|
||||||
|
|
||||||
|
| Attore | Come interagisce |
|
||||||
|
|---|---|
|
||||||
|
| <!-- DA COMPILARE: sistemi esterni, job pianificati, integrazioni --> | |
|
||||||
|
|
||||||
|
## 2. Persone
|
||||||
|
|
||||||
|
### 2.1 <!-- Nome — Ruolo -->
|
||||||
|
|
||||||
|
<!-- DA COMPILARE: chi è, cosa fa ogni giorno, cosa lo frustra oggi, cosa considera un successo. -->
|
||||||
|
|
||||||
|
## 3. Casi d'uso
|
||||||
|
|
||||||
|
### UC-01 — <!-- titolo come risultato: «Una richiesta completa diventa una proposta» -->
|
||||||
|
|
||||||
|
| | |
|
||||||
|
|---|---|
|
||||||
|
| **Attore** | |
|
||||||
|
| **Precondizioni** | |
|
||||||
|
| **Flusso principale** | 1. … 2. … 3. … |
|
||||||
|
| **Flussi alternativi** | |
|
||||||
|
| **Esito** | |
|
||||||
|
| **Requisiti** | `REQ-…` |
|
||||||
|
|
||||||
|
## 4. Matrice attore × caso d'uso
|
||||||
|
|
||||||
|
| Caso d'uso | <!-- attore 1 --> | <!-- attore 2 --> |
|
||||||
|
|---|:-:|:-:|
|
||||||
|
| UC-01 | ● | |
|
||||||
@@ -0,0 +1,62 @@
|
|||||||
|
# REQUIREMENTS — {{PROGETTO}}
|
||||||
|
|
||||||
|
Ultimo aggiornamento: **{{DATA}}** · Stato: **in stesura**
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Come leggere questo documento
|
||||||
|
|
||||||
|
Ogni requisito ha un identificativo `REQ-<AREA>-<nn>` immutabile, citato dalle specifiche
|
||||||
|
(`03-specs/`), dai task (`08-project/TODO.md`) e dalla matrice di tracciabilità
|
||||||
|
(`07-quality/TRACEABILITY.md`).
|
||||||
|
|
||||||
|
**Tipo:**
|
||||||
|
|
||||||
|
| Sigla | Significato |
|
||||||
|
|:-:|---|
|
||||||
|
| **P** | **Parità** — comportamento già presente nel sistema esistente, da riprodurre **identico**. Una differenza è una regressione. *(Solo per riscritture o evoluzioni.)* |
|
||||||
|
| **C** | **Correzione** — comportamento esistente difettoso, da correggere. Rimanda a un `DIF-nn`. |
|
||||||
|
| **N** | **Nuovo** — introdotto da questo progetto. |
|
||||||
|
|
||||||
|
**Origine:** dove il requisito è stato osservato o deciso: committente e data, `D-nnn`, oppure
|
||||||
|
`file:funzione` del codice esistente per i requisiti di parità.
|
||||||
|
|
||||||
|
> **Regola.** Un requisito descrive un comportamento osservabile e verificabile, non una
|
||||||
|
> soluzione tecnica. Modificare un requisito approvato è una decisione di prodotto e richiede
|
||||||
|
> una `D-nnn`.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Riepilogo
|
||||||
|
|
||||||
|
| Area | Codice | Requisiti | P | C | N |
|
||||||
|
|---|:-:|:-:|:-:|:-:|:-:|
|
||||||
|
| <!-- DA COMPILARE: es. Autenticazione e utenti --> | <!-- AUT --> | | | | |
|
||||||
|
| Non funzionali | NFR | | | | |
|
||||||
|
| **Totale** | | | | | |
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## <!-- AREA --> · <!-- Nome dell'area -->
|
||||||
|
|
||||||
|
| ID | Requisito | Tipo | Origine |
|
||||||
|
|---|---|:-:|---|
|
||||||
|
| <!-- **REQ-AREA-01** --> | <!-- DA COMPILARE: «Il sistema …», condizioni in grassetto, limiti numerici espliciti --> | N | <!-- committente, AAAA-MM-GG --> |
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## NFR · Non funzionali
|
||||||
|
|
||||||
|
| ID | Requisito | Tipo | Origine |
|
||||||
|
|---|---|:-:|---|
|
||||||
|
| <!-- **REQ-NFR-01** --> | <!-- DA COMPILARE: prestazioni, disponibilità, sicurezza, conservazione dei dati — sempre con un numero --> | N | |
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Difetti noti
|
||||||
|
|
||||||
|
Difetti del sistema esistente, o emersi durante il progetto, che un requisito di tipo **C** corregge.
|
||||||
|
|
||||||
|
| ID | Difetto | Effetto osservato | Requisito |
|
||||||
|
|---|---|---|---|
|
||||||
|
| <!-- **DIF-01** --> | | | `REQ-…` |
|
||||||
@@ -0,0 +1,52 @@
|
|||||||
|
# VISION — {{PROGETTO}}
|
||||||
|
|
||||||
|
Ultimo aggiornamento: **{{DATA}}** · Stato: **in stesura**
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 1. La frase che guida il prodotto
|
||||||
|
|
||||||
|
> <!-- DA COMPILARE: una frase sola, quella con cui si decide cosa entra e cosa no. -->
|
||||||
|
|
||||||
|
## 2. Il problema
|
||||||
|
|
||||||
|
<!-- DA COMPILARE: chi ha il problema, come lo risolve oggi, quanto costa (tempo, errori, denaro).
|
||||||
|
Preferire un dato misurato a un aggettivo. -->
|
||||||
|
|
||||||
|
## 3. Cosa fa il prodotto
|
||||||
|
|
||||||
|
<!-- DA COMPILARE: il flusso principale in 5-7 passi, dal punto di vista di chi lo usa. -->
|
||||||
|
|
||||||
|
## 4. Perché adesso
|
||||||
|
|
||||||
|
<!-- DA COMPILARE: cosa rende necessario il progetto ora (scadenza, cliente, limite del sistema attuale). -->
|
||||||
|
|
||||||
|
## 5. Cosa NON cambia
|
||||||
|
|
||||||
|
<!-- DA COMPILARE: vincoli fissi (sistemi esistenti, interfacce, abitudini degli utenti), oppure «non applicabile». -->
|
||||||
|
|
||||||
|
## 6. Perimetro
|
||||||
|
|
||||||
|
### Dentro il perimetro (primo rilascio)
|
||||||
|
|
||||||
|
- <!-- DA COMPILARE -->
|
||||||
|
|
||||||
|
### Fuori dal perimetro (esplicitamente)
|
||||||
|
|
||||||
|
- <!-- DA COMPILARE: ciò che qualcuno potrebbe aspettarsi e che NON si fa. Scriverlo evita discussioni dopo. -->
|
||||||
|
|
||||||
|
## 7. Come si misura il successo
|
||||||
|
|
||||||
|
| Indicatore | Valore attuale | Obiettivo |
|
||||||
|
|---|:-:|:-:|
|
||||||
|
| <!-- DA COMPILARE --> | | |
|
||||||
|
|
||||||
|
## 8. Rischi principali
|
||||||
|
|
||||||
|
| Rischio | Probabilità | Impatto | Contromisura |
|
||||||
|
|---|:-:|:-:|---|
|
||||||
|
| <!-- DA COMPILARE --> | | | |
|
||||||
|
|
||||||
|
## 9. Documenti collegati
|
||||||
|
|
||||||
|
[`REQUIREMENTS.md`](REQUIREMENTS.md) · [`PERSONAS_CASI_USO.md`](PERSONAS_CASI_USO.md) · [`../08-project/DECISIONS.md`](../08-project/DECISIONS.md)
|
||||||
+52
@@ -0,0 +1,52 @@
|
|||||||
|
# ARCHITECTURE — {{PROGETTO}}
|
||||||
|
|
||||||
|
Ultimo aggiornamento: **{{DATA}}** · Stato: **in stesura**
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 1. Vista d'insieme
|
||||||
|
|
||||||
|
```
|
||||||
|
<!-- DA COMPILARE: schema ASCII dei servizi e delle frecce principali -->
|
||||||
|
```
|
||||||
|
|
||||||
|
## 2. Servizi
|
||||||
|
|
||||||
|
| Servizio | Tecnologia | Responsabilità | Non fa |
|
||||||
|
|---|---|---|---|
|
||||||
|
| <!-- DA COMPILARE --> | | | |
|
||||||
|
|
||||||
|
<!-- Per ogni scelta non ovvia («perché due servizi e non uno») una sottosezione breve che
|
||||||
|
rimanda alla D-xxx. -->
|
||||||
|
|
||||||
|
## 3. Flusso principale
|
||||||
|
|
||||||
|
<!-- DA COMPILARE: il caso d'uso UC-01 attraverso i servizi, passo per passo, con le code e i dati scambiati. -->
|
||||||
|
|
||||||
|
## 4. Code e lavori asincroni
|
||||||
|
|
||||||
|
| Coda / lavoro | Produttore | Consumatore | Tentativi | Cosa succede se fallisce |
|
||||||
|
|---|---|---|:-:|---|
|
||||||
|
| <!-- DA COMPILARE o «non applicabile» --> | | | | |
|
||||||
|
|
||||||
|
## 5. Configurazione
|
||||||
|
|
||||||
|
<!-- DA COMPILARE: cosa è variabile d'ambiente, cosa è configurazione a caldo, cosa è segreto. -->
|
||||||
|
|
||||||
|
## 6. Multi-tenancy e isolamento
|
||||||
|
|
||||||
|
<!-- DA COMPILARE o «non applicabile». -->
|
||||||
|
|
||||||
|
## 7. Integrazioni esterne
|
||||||
|
|
||||||
|
| Sistema | Direzione | Protocollo | Contratto |
|
||||||
|
|---|---|---|---|
|
||||||
|
| <!-- DA COMPILARE --> | | | |
|
||||||
|
|
||||||
|
## 8. Ambienti
|
||||||
|
|
||||||
|
Vedi [`../06-devops/ENVIRONMENTS.md`](../06-devops/ENVIRONMENTS.md).
|
||||||
|
|
||||||
|
## 9. Documenti collegati
|
||||||
|
|
||||||
|
[`C4_MODEL.md`](C4_MODEL.md) · [`DATA_MODEL.md`](DATA_MODEL.md) · [`DOMAIN_WORKFLOW.md`](DOMAIN_WORKFLOW.md) · [`SECURITY.md`](SECURITY.md)
|
||||||
+35
@@ -0,0 +1,35 @@
|
|||||||
|
# C4 MODEL — Contesto, Contenitori, Componenti
|
||||||
|
|
||||||
|
Ultimo aggiornamento: **{{DATA}}**
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Livello 1 · Contesto
|
||||||
|
|
||||||
|
```
|
||||||
|
<!-- DA COMPILARE: il sistema al centro, attori e sistemi esterni intorno -->
|
||||||
|
```
|
||||||
|
|
||||||
|
| Attore / sistema esterno | Relazione con {{PROGETTO}} |
|
||||||
|
|---|---|
|
||||||
|
| <!-- DA COMPILARE --> | |
|
||||||
|
|
||||||
|
## Livello 2 · Contenitori
|
||||||
|
|
||||||
|
| Contenitore | Tecnologia | Parla con | Porta / protocollo |
|
||||||
|
|---|---|---|---|
|
||||||
|
| <!-- DA COMPILARE --> | | | |
|
||||||
|
|
||||||
|
## Livello 3 · Componenti
|
||||||
|
|
||||||
|
### 3.1 <!-- Contenitore -->
|
||||||
|
|
||||||
|
| Componente | Responsabilità | Spec |
|
||||||
|
|---|---|---|
|
||||||
|
| <!-- DA COMPILARE --> | | `SPEC-…` |
|
||||||
|
|
||||||
|
## 4. Corrispondenza fra i livelli e i requisiti
|
||||||
|
|
||||||
|
| Componente | Requisiti |
|
||||||
|
|---|---|
|
||||||
|
| <!-- DA COMPILARE --> | `REQ-…` |
|
||||||
+42
@@ -0,0 +1,42 @@
|
|||||||
|
# DATA MODEL — Entità, relazioni, invarianti
|
||||||
|
|
||||||
|
Ultimo aggiornamento: **{{DATA}}**
|
||||||
|
|
||||||
|
Modello **logico**. Lo schema fisico (tipi, indici, migrazioni) è in
|
||||||
|
[`../05-data/DATABASE.md`](../05-data/DATABASE.md).
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 1. Mappa delle entità
|
||||||
|
|
||||||
|
```
|
||||||
|
<!-- DA COMPILARE: entità e cardinalità, es. Tenant 1──* Utente -->
|
||||||
|
```
|
||||||
|
|
||||||
|
## 2. Entità
|
||||||
|
|
||||||
|
### 2.1 <!-- Entità -->
|
||||||
|
|
||||||
|
| Attributo | Significato | Obbligatorio | Note |
|
||||||
|
|---|---|:-:|---|
|
||||||
|
| <!-- DA COMPILARE --> | | | |
|
||||||
|
|
||||||
|
**Ciclo di vita:** <!-- chi la crea, chi la modifica, quando si cancella -->
|
||||||
|
|
||||||
|
## 3. Chiavi naturali e univocità
|
||||||
|
|
||||||
|
| Entità | Univoca per |
|
||||||
|
|---|---|
|
||||||
|
| <!-- DA COMPILARE --> | |
|
||||||
|
|
||||||
|
## 4. Cancellazioni
|
||||||
|
|
||||||
|
| Entità | Cancellazione | Effetto sui figli |
|
||||||
|
|---|---|---|
|
||||||
|
| <!-- DA COMPILARE: fisica, logica (soft delete), vietata --> | | |
|
||||||
|
|
||||||
|
## 5. Invarianti del modello
|
||||||
|
|
||||||
|
| # | Invariante |
|
||||||
|
|:-:|---|
|
||||||
|
| M1 | <!-- DA COMPILARE --> |
|
||||||
+35
@@ -0,0 +1,35 @@
|
|||||||
|
# DOMAIN WORKFLOW — Stati, transizioni, invarianti
|
||||||
|
|
||||||
|
Ultimo aggiornamento: **{{DATA}}**
|
||||||
|
|
||||||
|
<!-- Se il dominio non ha un ciclo di vita con stati, scrivere «non applicabile» e il perché. -->
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 1. Stati
|
||||||
|
|
||||||
|
| Stato | Significato | Terminale |
|
||||||
|
|---|---|:-:|
|
||||||
|
| <!-- DA COMPILARE --> | | |
|
||||||
|
|
||||||
|
## 2. Macchina a stati
|
||||||
|
|
||||||
|
```
|
||||||
|
<!-- DA COMPILARE: diagramma ASCII degli stati -->
|
||||||
|
```
|
||||||
|
|
||||||
|
## 3. Transizioni ammesse
|
||||||
|
|
||||||
|
Qualsiasi transizione non elencata qui è **rifiutata**.
|
||||||
|
|
||||||
|
| # | Da | A | Attore | Condizione | Effetti collaterali |
|
||||||
|
|:-:|---|---|---|---|---|
|
||||||
|
| T1 | | | | | |
|
||||||
|
|
||||||
|
## 4. Invarianti
|
||||||
|
|
||||||
|
Condizioni che devono essere vere **sempre**, verificate da test.
|
||||||
|
|
||||||
|
| # | Invariante |
|
||||||
|
|:-:|---|
|
||||||
|
| I1 | <!-- DA COMPILARE --> |
|
||||||
+44
@@ -0,0 +1,44 @@
|
|||||||
|
# SECURITY — Modello di sicurezza
|
||||||
|
|
||||||
|
Ultimo aggiornamento: **{{DATA}}**
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 1. Perimetro
|
||||||
|
|
||||||
|
<!-- DA COMPILARE: cosa è esposto a Internet, cosa resta interno. -->
|
||||||
|
|
||||||
|
## 2. Autenticazione
|
||||||
|
|
||||||
|
<!-- DA COMPILARE: meccanismo, durata dei token, rotte pubbliche (elenco chiuso: aggiungerne una richiede una D-xxx). -->
|
||||||
|
|
||||||
|
## 3. Autorizzazione
|
||||||
|
|
||||||
|
| Ruolo | Può | Non può |
|
||||||
|
|---|---|---|
|
||||||
|
| <!-- DA COMPILARE --> | | |
|
||||||
|
|
||||||
|
Regola: nessuno crea un utente più potente di sé.
|
||||||
|
|
||||||
|
## 4. Segreti
|
||||||
|
|
||||||
|
- I segreti non entrano mai nel repository, nei log o nella documentazione.
|
||||||
|
- <!-- DA COMPILARE: dove vivono (variabili d'ambiente, secret manager, cifrati a riposo). -->
|
||||||
|
|
||||||
|
## 5. Dati in ingresso e in uscita
|
||||||
|
|
||||||
|
<!-- DA COMPILARE: validazione, dimensioni massime, dati personali, cosa esce verso terzi. -->
|
||||||
|
|
||||||
|
## 6. Audit
|
||||||
|
|
||||||
|
<!-- DA COMPILARE: quali eventi si registrano, dove, per quanto tempo. -->
|
||||||
|
|
||||||
|
## 7. Minacce e contromisure
|
||||||
|
|
||||||
|
| Minaccia | Contromisura | Verificata da |
|
||||||
|
|---|---|---|
|
||||||
|
| <!-- DA COMPILARE --> | | test / `REQ-…` |
|
||||||
|
|
||||||
|
## 8. Cosa resta aperto
|
||||||
|
|
||||||
|
<!-- DA COMPILARE -->
|
||||||
@@ -0,0 +1,59 @@
|
|||||||
|
# API — Catalogo e convenzioni
|
||||||
|
|
||||||
|
Ultimo aggiornamento: **{{DATA}}**
|
||||||
|
|
||||||
|
Il contratto è [`openapi.yaml`](openapi.yaml), **fonte di verità**: in caso di differenza fra
|
||||||
|
questo documento, il codice e il contratto, vale il contratto. Si scrive il contratto **prima**
|
||||||
|
del codice (contract-first).
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 1. Convenzioni
|
||||||
|
|
||||||
|
| Aspetto | Regola |
|
||||||
|
|---|---|
|
||||||
|
| Prefisso | `/api/v1` |
|
||||||
|
| Formato | JSON, UTF-8, date ISO 8601 in UTC |
|
||||||
|
| Nomi | <!-- DA COMPILARE: snake_case o camelCase, una sola scelta --> |
|
||||||
|
| Autenticazione | <!-- DA COMPILARE --> |
|
||||||
|
|
||||||
|
## 2. Errori
|
||||||
|
|
||||||
|
Forma unica per tutti gli errori:
|
||||||
|
|
||||||
|
```json
|
||||||
|
{ "error": { "code": "stringa_stabile", "message": "testo leggibile", "details": {} } }
|
||||||
|
```
|
||||||
|
|
||||||
|
| Codice HTTP | Quando |
|
||||||
|
|:-:|---|
|
||||||
|
| 400 | Richiesta malformata |
|
||||||
|
| 401 | Non autenticato |
|
||||||
|
| 403 | Autenticato ma non autorizzato |
|
||||||
|
| 404 | Risorsa inesistente **o di un altro tenant** (non si rivela l'esistenza) |
|
||||||
|
| 409 | Conflitto (duplicato, stato non compatibile) |
|
||||||
|
| 422 | Validazione fallita |
|
||||||
|
|
||||||
|
## 3. Paginazione
|
||||||
|
|
||||||
|
<!-- DA COMPILARE: parametri (page/size o cursore), limiti massimi, forma della risposta. -->
|
||||||
|
|
||||||
|
## 4. Catalogo
|
||||||
|
|
||||||
|
### <!-- Gruppo --> — `SPEC-…`
|
||||||
|
|
||||||
|
| Metodo | Percorso | Ruolo minimo | Descrizione |
|
||||||
|
|---|---|---|---|
|
||||||
|
| <!-- DA COMPILARE --> | | | |
|
||||||
|
|
||||||
|
## 5. API interne — non esposte
|
||||||
|
|
||||||
|
<!-- DA COMPILARE o «nessuna». -->
|
||||||
|
|
||||||
|
## 6. Idempotenza e concorrenza
|
||||||
|
|
||||||
|
<!-- DA COMPILARE: chiavi di idempotenza, controllo delle versioni, comportamento in caso di doppio invio. -->
|
||||||
|
|
||||||
|
## 7. Limiti
|
||||||
|
|
||||||
|
<!-- DA COMPILARE: rate limit, dimensioni massime dei corpi e dei file. -->
|
||||||
@@ -0,0 +1,54 @@
|
|||||||
|
# Contratto pubblico di {{PROGETTO}} — FONTE DI VERITÀ (D-002).
|
||||||
|
# Si modifica PRIMA del codice. Ogni operazione cita la spec che la definisce.
|
||||||
|
openapi: 3.1.0
|
||||||
|
info:
|
||||||
|
title: "{{PROGETTO}} API"
|
||||||
|
version: 0.1.0
|
||||||
|
description: |
|
||||||
|
Contratto dell'API di {{PROGETTO}}.
|
||||||
|
Documentazione redatta con il metodo spec-driven di STS Lab Srl.
|
||||||
|
servers:
|
||||||
|
- url: /api/v1
|
||||||
|
tags:
|
||||||
|
- name: health
|
||||||
|
description: Stato del servizio
|
||||||
|
paths:
|
||||||
|
/health:
|
||||||
|
get:
|
||||||
|
tags: [health]
|
||||||
|
summary: Stato del servizio
|
||||||
|
security: []
|
||||||
|
responses:
|
||||||
|
"200":
|
||||||
|
description: Servizio attivo
|
||||||
|
content:
|
||||||
|
application/json:
|
||||||
|
schema:
|
||||||
|
type: object
|
||||||
|
properties:
|
||||||
|
status:
|
||||||
|
type: string
|
||||||
|
example: ok
|
||||||
|
components:
|
||||||
|
securitySchemes:
|
||||||
|
BearerAuth:
|
||||||
|
type: http
|
||||||
|
scheme: bearer
|
||||||
|
bearerFormat: JWT
|
||||||
|
schemas:
|
||||||
|
Error:
|
||||||
|
type: object
|
||||||
|
required: [error]
|
||||||
|
properties:
|
||||||
|
error:
|
||||||
|
type: object
|
||||||
|
required: [code, message]
|
||||||
|
properties:
|
||||||
|
code:
|
||||||
|
type: string
|
||||||
|
message:
|
||||||
|
type: string
|
||||||
|
details:
|
||||||
|
type: object
|
||||||
|
security:
|
||||||
|
- BearerAuth: []
|
||||||
@@ -0,0 +1,47 @@
|
|||||||
|
# DATABASE — Schema fisico
|
||||||
|
|
||||||
|
Ultimo aggiornamento: **{{DATA}}**
|
||||||
|
|
||||||
|
Traduzione fisica di [`../02-architecture/DATA_MODEL.md`](../02-architecture/DATA_MODEL.md).
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 1. Convenzioni
|
||||||
|
|
||||||
|
| Aspetto | Regola |
|
||||||
|
|---|---|
|
||||||
|
| Motore | <!-- DA COMPILARE: es. PostgreSQL 16 --> |
|
||||||
|
| Nomi | tabelle al singolare, `snake_case` |
|
||||||
|
| Chiavi primarie | <!-- DA COMPILARE: UUID / bigint --> |
|
||||||
|
| Date | `timestamptz`, sempre UTC |
|
||||||
|
| Multi-tenancy | <!-- DA COMPILARE: colonna `tenant_id` su ogni tabella di dominio, o «non applicabile» --> |
|
||||||
|
|
||||||
|
## 2. Tipi enumerati
|
||||||
|
|
||||||
|
| Tipo | Valori |
|
||||||
|
|---|---|
|
||||||
|
| <!-- DA COMPILARE --> | |
|
||||||
|
|
||||||
|
## 3. Tabelle
|
||||||
|
|
||||||
|
### `<!-- tabella -->`
|
||||||
|
|
||||||
|
| Colonna | Tipo | Null | Default | Note |
|
||||||
|
|---|---|:-:|---|---|
|
||||||
|
| `id` | | no | | PK |
|
||||||
|
|
||||||
|
Indici: <!-- DA COMPILARE --> · Vincoli: <!-- DA COMPILARE -->
|
||||||
|
|
||||||
|
## 4. Vincoli che riflettono requisiti
|
||||||
|
|
||||||
|
| Vincolo | Requisito |
|
||||||
|
|---|---|
|
||||||
|
| <!-- DA COMPILARE --> | `REQ-…` |
|
||||||
|
|
||||||
|
## 5. Migrazioni
|
||||||
|
|
||||||
|
<!-- DA COMPILARE: strumento (es. Alembic), regola «una migrazione per modifica, mai riscrivere una migrazione già applicata». -->
|
||||||
|
|
||||||
|
## 6. Dimensionamento
|
||||||
|
|
||||||
|
<!-- DA COMPILARE: volumi attesi per tabella a 1 e 3 anni. -->
|
||||||
@@ -0,0 +1,30 @@
|
|||||||
|
# SEED E BOOTSTRAP — Stato iniziale del sistema
|
||||||
|
|
||||||
|
Ultimo aggiornamento: **{{DATA}}**
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 1. Principio
|
||||||
|
|
||||||
|
Il bootstrap è **idempotente**: eseguirlo due volte produce lo stesso stato di eseguirlo una.
|
||||||
|
|
||||||
|
## 2. Cosa viene creato
|
||||||
|
|
||||||
|
| Elemento | Quando | Origine dei valori |
|
||||||
|
|---|---|---|
|
||||||
|
| <!-- DA COMPILARE: utente amministratore iniziale, configurazione di base --> | primo avvio | variabili d'ambiente |
|
||||||
|
|
||||||
|
## 3. Credenziali iniziali
|
||||||
|
|
||||||
|
In collaudo e produzione l'avvio **fallisce** se le credenziali di bootstrap sono lasciate ai
|
||||||
|
valori predefiniti.
|
||||||
|
|
||||||
|
## 4. Variabili di bootstrap
|
||||||
|
|
||||||
|
| Variabile | Obbligatoria | Significato |
|
||||||
|
|---|:-:|---|
|
||||||
|
| <!-- DA COMPILARE --> | | |
|
||||||
|
|
||||||
|
## 5. Dati di prova per lo sviluppo
|
||||||
|
|
||||||
|
<!-- DA COMPILARE: come si generano, e la regola che non arrivano mai in produzione. -->
|
||||||
@@ -0,0 +1,34 @@
|
|||||||
|
# BACKUP E RIPRISTINO
|
||||||
|
|
||||||
|
Ultimo aggiornamento: **{{DATA}}**
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 1. Cosa va salvato
|
||||||
|
|
||||||
|
| Dato | Dove vive | Ricostruibile | Backup |
|
||||||
|
|---|---|:-:|---|
|
||||||
|
| <!-- DA COMPILARE --> | | | |
|
||||||
|
|
||||||
|
## 2. Obiettivi
|
||||||
|
|
||||||
|
| Obiettivo | Valore |
|
||||||
|
|---|---|
|
||||||
|
| RPO (dati che si accetta di perdere) | <!-- DA COMPILARE --> |
|
||||||
|
| RTO (tempo per tornare operativi) | <!-- DA COMPILARE --> |
|
||||||
|
|
||||||
|
## 3. Procedura di ripristino
|
||||||
|
|
||||||
|
1. <!-- DA COMPILARE -->
|
||||||
|
|
||||||
|
## 4. Verifiche dopo un ripristino
|
||||||
|
|
||||||
|
- [ ] <!-- DA COMPILARE -->
|
||||||
|
|
||||||
|
## 5. Prova di ripristino
|
||||||
|
|
||||||
|
Un backup mai ripristinato non è un backup. Prova <!-- DA COMPILARE: frequenza -->, esito registrato in `DEVELOPMENT_LOG`.
|
||||||
|
|
||||||
|
## 6. Cosa non è coperto
|
||||||
|
|
||||||
|
<!-- DA COMPILARE -->
|
||||||
@@ -0,0 +1,31 @@
|
|||||||
|
# CI/CD — Integrazione e rilascio
|
||||||
|
|
||||||
|
Ultimo aggiornamento: **{{DATA}}**
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 1. Flussi
|
||||||
|
|
||||||
|
| Flusso | Innesco | Ambiente di destinazione |
|
||||||
|
|---|---|---|
|
||||||
|
| <!-- DA COMPILARE --> | | |
|
||||||
|
|
||||||
|
## 2. Sequenza
|
||||||
|
|
||||||
|
1. <!-- DA COMPILARE: build, test, analisi, immagini, deploy -->
|
||||||
|
|
||||||
|
## 3. Verifiche in pipeline
|
||||||
|
|
||||||
|
| Verifica | Perché | Blocca il rilascio |
|
||||||
|
|---|---|:-:|
|
||||||
|
| Test automatici | criteri di accettazione delle spec | sì |
|
||||||
|
| Ricerca di segreti | nessun segreto nel repository | sì |
|
||||||
|
| Contratto contro implementazione | il codice rispetta `openapi.yaml` | sì |
|
||||||
|
|
||||||
|
## 4. Segreti della pipeline
|
||||||
|
|
||||||
|
<!-- DA COMPILARE -->
|
||||||
|
|
||||||
|
## 5. Rilascio in produzione e rientro
|
||||||
|
|
||||||
|
<!-- DA COMPILARE: chi approva, come si torna alla versione precedente, in quanto tempo. -->
|
||||||
@@ -0,0 +1,31 @@
|
|||||||
|
# ENVIRONMENTS — Sviluppo, collaudo, produzione
|
||||||
|
|
||||||
|
Ultimo aggiornamento: **{{DATA}}**
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 1. Gli ambienti
|
||||||
|
|
||||||
|
| Ambiente | Scopo | Dati | Chi vi accede |
|
||||||
|
|---|---|---|---|
|
||||||
|
| dev | sviluppo | di prova | sviluppatori |
|
||||||
|
| qa | collaudo | di prova, realistici | sviluppatori, committente |
|
||||||
|
| prod | esercizio | reali | utenti |
|
||||||
|
|
||||||
|
## 2. Variabili di configurazione
|
||||||
|
|
||||||
|
| Variabile | Significato | dev | qa | prod | Segreta |
|
||||||
|
|---|---|---|---|---|:-:|
|
||||||
|
| <!-- DA COMPILARE --> | | | | | |
|
||||||
|
|
||||||
|
## 3. Ambiente locale di sviluppo
|
||||||
|
|
||||||
|
<!-- DA COMPILARE: comandi per avviare tutto in locale (es. docker compose up). -->
|
||||||
|
|
||||||
|
## 4. Promozione fra ambienti
|
||||||
|
|
||||||
|
<!-- DA COMPILARE: dev → qa → prod, chi approva, cosa si verifica a ogni passo. -->
|
||||||
|
|
||||||
|
## 5. Prima di dichiarare un ambiente pronto
|
||||||
|
|
||||||
|
- [ ] <!-- DA COMPILARE -->
|
||||||
+31
@@ -0,0 +1,31 @@
|
|||||||
|
# INFRASTRUCTURE — Topologia e risorse
|
||||||
|
|
||||||
|
Ultimo aggiornamento: **{{DATA}}**
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 1. Topologia
|
||||||
|
|
||||||
|
```
|
||||||
|
<!-- DA COMPILARE: nodi, servizi, rete -->
|
||||||
|
```
|
||||||
|
|
||||||
|
## 2. Servizi e risorse
|
||||||
|
|
||||||
|
| Servizio | Immagine / runtime | Repliche | CPU | Memoria |
|
||||||
|
|---|---|:-:|---|---|
|
||||||
|
| <!-- DA COMPILARE --> | | | | |
|
||||||
|
|
||||||
|
## 3. Persistenza
|
||||||
|
|
||||||
|
| Volume / storage | Contenuto | Dimensione | Backup |
|
||||||
|
|---|---|---|:-:|
|
||||||
|
| <!-- DA COMPILARE --> | | | |
|
||||||
|
|
||||||
|
## 4. Rete, nomi e certificati
|
||||||
|
|
||||||
|
<!-- DA COMPILARE: domini, ingress, TLS, porte esposte. -->
|
||||||
|
|
||||||
|
## 5. Capacità e crescita
|
||||||
|
|
||||||
|
<!-- DA COMPILARE -->
|
||||||
@@ -0,0 +1,37 @@
|
|||||||
|
# OBSERVABILITY — Log, metriche, allarmi
|
||||||
|
|
||||||
|
Ultimo aggiornamento: **{{DATA}}**
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 1. Il problema che risolve
|
||||||
|
|
||||||
|
<!-- DA COMPILARE: quali domande operative si devono poter rispondere senza aprire il database. -->
|
||||||
|
|
||||||
|
## 2. Log
|
||||||
|
|
||||||
|
| Aspetto | Regola |
|
||||||
|
|---|---|
|
||||||
|
| Formato | JSON strutturato |
|
||||||
|
| Correlazione | un identificativo di richiesta propagato fra i servizi |
|
||||||
|
| Mai nei log | password, token, segreti, dati personali non necessari |
|
||||||
|
|
||||||
|
## 3. Metriche
|
||||||
|
|
||||||
|
| Metrica | Tipo | Significato |
|
||||||
|
|---|---|---|
|
||||||
|
| <!-- DA COMPILARE --> | | |
|
||||||
|
|
||||||
|
## 4. Allarmi
|
||||||
|
|
||||||
|
| Allarme | Condizione | Gravità | Procedura |
|
||||||
|
|---|---|:-:|---|
|
||||||
|
| <!-- DA COMPILARE --> | | | [`RUNBOOK`](RUNBOOK.md) §… |
|
||||||
|
|
||||||
|
## 5. Salute
|
||||||
|
|
||||||
|
`GET /health` — <!-- DA COMPILARE: cosa verifica. -->
|
||||||
|
|
||||||
|
## 6. Conservazione
|
||||||
|
|
||||||
|
<!-- DA COMPILARE -->
|
||||||
@@ -0,0 +1,25 @@
|
|||||||
|
# RUNBOOK — Procedure operative
|
||||||
|
|
||||||
|
Ultimo aggiornamento: **{{DATA}}**
|
||||||
|
|
||||||
|
Ogni procedura segue lo stesso schema: **sintomo → verifica → azione → conferma**.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 1. <!-- Sintomo, come lo descriverebbe chi lo nota -->
|
||||||
|
|
||||||
|
| Passo | Cosa fare |
|
||||||
|
|---|---|
|
||||||
|
| **Verifica** | <!-- comando o schermata --> |
|
||||||
|
| **Azione** | |
|
||||||
|
| **Conferma** | |
|
||||||
|
|
||||||
|
## 2. Ripristino da backup
|
||||||
|
|
||||||
|
Vedi [`BACKUP_DR.md`](BACKUP_DR.md) §… .
|
||||||
|
|
||||||
|
## 3. Contatti e riferimenti
|
||||||
|
|
||||||
|
| Ruolo | Contatto |
|
||||||
|
|---|---|
|
||||||
|
| <!-- DA COMPILARE --> | |
|
||||||
+35
@@ -0,0 +1,35 @@
|
|||||||
|
# ACCEPTANCE CRITERIA — Criteri di rilascio
|
||||||
|
|
||||||
|
Ultimo aggiornamento: **{{DATA}}**
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 1. Riepilogo per specifica
|
||||||
|
|
||||||
|
| Spec | Criteri | Verificati | Stato |
|
||||||
|
|---|:-:|:-:|:-:|
|
||||||
|
| <!-- SPEC-001 --> | | | ⬜ |
|
||||||
|
|
||||||
|
## 2. Criteri di rilascio — versione <!-- x.y.z -->
|
||||||
|
|
||||||
|
### 2.1 Bloccanti
|
||||||
|
|
||||||
|
| # | Criterio | Verificato da |
|
||||||
|
|:-:|---|---|
|
||||||
|
| R1 | Tutti i test passano in pipeline | CI |
|
||||||
|
| R2 | Nessuna riga scoperta in `TRACEABILITY.md` | revisione |
|
||||||
|
| R3 | <!-- DA COMPILARE --> | |
|
||||||
|
|
||||||
|
### 2.2 Attesi (non bloccanti)
|
||||||
|
|
||||||
|
| # | Criterio |
|
||||||
|
|:-:|---|
|
||||||
|
| <!-- DA COMPILARE --> | |
|
||||||
|
|
||||||
|
## 3. Verifica funzionale prima del rilascio
|
||||||
|
|
||||||
|
- [ ] <!-- DA COMPILARE: percorsi da provare a mano con il committente -->
|
||||||
|
|
||||||
|
## 4. Cosa non è criterio di rilascio
|
||||||
|
|
||||||
|
<!-- DA COMPILARE -->
|
||||||
+38
@@ -0,0 +1,38 @@
|
|||||||
|
# TEST STRATEGY
|
||||||
|
|
||||||
|
Ultimo aggiornamento: **{{DATA}}**
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 1. Il criterio
|
||||||
|
|
||||||
|
Ogni criterio di accettazione di ogni spec ha **almeno un test eseguito**. Lo stato di un
|
||||||
|
requisito in [`TRACEABILITY.md`](TRACEABILITY.md) diventa ✅ quando il test passa, non quando
|
||||||
|
il codice è scritto. Ogni difetto `DIF-nn` ha un test che lo riproduce.
|
||||||
|
|
||||||
|
## 2. Livelli
|
||||||
|
|
||||||
|
| Livello | Cosa verifica | Strumento | Dove |
|
||||||
|
|---|---|---|---|
|
||||||
|
| Unitario | funzioni pure, regole di business | <!-- DA COMPILARE --> | |
|
||||||
|
| Integrazione | servizi + database + code, con simulatori dei sistemi esterni | | |
|
||||||
|
| Contratto | implementazione contro `openapi.yaml` | | |
|
||||||
|
| End-to-end | casi d'uso dall'interfaccia | | |
|
||||||
|
|
||||||
|
## 3. Simulatori dei sistemi esterni
|
||||||
|
|
||||||
|
| Sistema | Simulatore | Comportamenti simulati (anche i guasti) |
|
||||||
|
|---|---|---|
|
||||||
|
| <!-- DA COMPILARE --> | | |
|
||||||
|
|
||||||
|
## 4. Nominare i test
|
||||||
|
|
||||||
|
Il nome del test cita il criterio: `test_D3_sufficiente_urgente_ricorrente_lotto_grande_priorita_1`.
|
||||||
|
|
||||||
|
## 5. Esecuzione
|
||||||
|
|
||||||
|
<!-- DA COMPILARE: comandi, durata attesa, numero di test (aggiornato in DEVELOPMENT_LOG). -->
|
||||||
|
|
||||||
|
## 6. Cosa non verifichiamo
|
||||||
|
|
||||||
|
<!-- DA COMPILARE, con il perché. -->
|
||||||
@@ -0,0 +1,48 @@
|
|||||||
|
# TRACEABILITY — Matrice REQ → SPEC → T → test
|
||||||
|
|
||||||
|
Ultimo aggiornamento: **{{DATA}}** · Stato: **in stesura**
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 1. Regola
|
||||||
|
|
||||||
|
> **Nessuna riga vuota.** Ogni requisito ha una specifica, ogni specifica ha task, ogni task ha
|
||||||
|
> test. Un requisito senza spec non è implementabile; un task senza spec non entra in lavorazione.
|
||||||
|
|
||||||
|
La colonna *Stato* si compila durante l'implementazione: ⬜ da fare · 🟡 in corso · ✅ verificato.
|
||||||
|
Lo stato si aggiorna **quando il test passa, non quando il codice è scritto**.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 2. Copertura
|
||||||
|
|
||||||
|
| Area | REQ | Spec | Task | Criteri | Copertura |
|
||||||
|
|---|:-:|---|---|:-:|:-:|
|
||||||
|
| <!-- DA COMPILARE --> | | | | | ⬜ |
|
||||||
|
| **Totale** | | | | | |
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 3. Matrice per requisito
|
||||||
|
|
||||||
|
### <!-- AREA --> · <!-- Nome -->
|
||||||
|
|
||||||
|
| REQ | Spec | Task | Criteri | Stato |
|
||||||
|
|---|---|---|---|:-:|
|
||||||
|
| <!-- AREA-01 --> | <!-- SPEC-001 §2 --> | <!-- T-010 --> | <!-- A1 --> | ⬜ |
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 4. Decisioni → specifiche
|
||||||
|
|
||||||
|
| Decisione | Dove si applica | Task |
|
||||||
|
|---|---|---|
|
||||||
|
| D-002 | metodo | — |
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 5. Difetti → test
|
||||||
|
|
||||||
|
| Difetto | Requisito | Test |
|
||||||
|
|---|---|---|
|
||||||
|
| <!-- DIF-01 --> | | |
|
||||||
@@ -0,0 +1,14 @@
|
|||||||
|
# CHANGELOG
|
||||||
|
|
||||||
|
Formato: [Keep a Changelog](https://keepachangelog.com/it/1.1.0/) · Versionamento semantico.
|
||||||
|
|
||||||
|
Le voci descrivono ciò che cambia **per chi usa il prodotto**. Le decisioni tecniche stanno in
|
||||||
|
[`DECISIONS.md`](DECISIONS.md), il diario di lavoro in [`DEVELOPMENT_LOG.md`](DEVELOPMENT_LOG.md).
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## [Non rilasciato] — 0.1.0
|
||||||
|
|
||||||
|
### Aggiunto
|
||||||
|
|
||||||
|
- Documentazione di progetto con metodo spec-driven ({{DATA}}).
|
||||||
@@ -0,0 +1,83 @@
|
|||||||
|
# DECISIONS — Registro delle decisioni architetturali (ADR)
|
||||||
|
|
||||||
|
Ultimo aggiornamento: **{{DATA}}** · Progetto: **{{PROGETTO}}**
|
||||||
|
|
||||||
|
Ogni decisione strutturale del progetto è registrata qui con un identificativo `D-xxx` immutabile.
|
||||||
|
Le decisioni si **superano**, non si cancellano: una decisione sbagliata resta a registro con stato
|
||||||
|
*Superata da D-yyy*, così la storia del progetto resta leggibile.
|
||||||
|
|
||||||
|
**Stati:** `Proposta` · `Accettata` · `Superata da D-xxx` · `Respinta`
|
||||||
|
|
||||||
|
**Formato:** Contesto → Decisione → Alternative valutate → Conseguenze.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Indice
|
||||||
|
|
||||||
|
| ID | Titolo | Stato | Data |
|
||||||
|
|---|---|---|---|
|
||||||
|
| [D-001](#d-001--stack-tecnologico) | Stack tecnologico | Proposta | {{DATA}} |
|
||||||
|
| [D-002](#d-002--sviluppo-spec-driven-vincolante) | Sviluppo spec-driven vincolante | Accettata | {{DATA}} |
|
||||||
|
| [D-003](#d-003--la-documentazione-vive-nel-repository) | La documentazione vive nel repository | Accettata | {{DATA}} |
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## D-001 — Stack tecnologico
|
||||||
|
|
||||||
|
**Stato:** Proposta · {{DATA}}
|
||||||
|
|
||||||
|
### Contesto
|
||||||
|
<!-- DA COMPILARE: vincoli del committente, competenze, sistemi esistenti con cui integrarsi. -->
|
||||||
|
|
||||||
|
### Decisione
|
||||||
|
<!-- DA COMPILARE: linguaggi, framework, database, code, storage, deploy. -->
|
||||||
|
|
||||||
|
### Alternative valutate
|
||||||
|
- <!-- DA COMPILARE: alternativa — perché scartata. -->
|
||||||
|
|
||||||
|
### Conseguenze
|
||||||
|
- <!-- DA COMPILARE -->
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## D-002 — Sviluppo spec-driven vincolante
|
||||||
|
|
||||||
|
**Stato:** Accettata · {{DATA}}
|
||||||
|
|
||||||
|
### Contesto
|
||||||
|
Le regole di business scritte solo nel codice emergono dal debugging invece che dalla
|
||||||
|
specifica, e si scoprono quando un difetto le rivela.
|
||||||
|
|
||||||
|
### Decisione
|
||||||
|
Nessuna implementazione senza una `SPEC-xxx` in stato *Approvata*. Ogni spec contiene: contesto,
|
||||||
|
requisiti coperti (`REQ-xxx`), contratto API, modello dati, regole, casi di errore, criteri di
|
||||||
|
accettazione, task derivati (`T-xxx`). `07-quality/TRACEABILITY.md` mantiene la matrice
|
||||||
|
REQ → SPEC → T → test e non deve avere righe vuote. Il contratto API (`04-api/openapi.yaml`) è
|
||||||
|
la fonte di verità e si scrive prima del codice.
|
||||||
|
|
||||||
|
### Alternative valutate
|
||||||
|
- **Documentazione a valle del codice.** Produce documenti veri ma tardivi; le regole restano
|
||||||
|
scoperte finché un bug non le rivela.
|
||||||
|
|
||||||
|
### Conseguenze
|
||||||
|
- La fase di documentazione precede quella di codice; il codice inizia più tardi e procede più dritto.
|
||||||
|
- Una spec approvata si modifica solo con una nuova `D-xxx` o una revisione tracciata.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## D-003 — La documentazione vive nel repository
|
||||||
|
|
||||||
|
**Stato:** Accettata · {{DATA}}
|
||||||
|
|
||||||
|
### Contesto
|
||||||
|
Documentazione e codice divergono quando vivono in luoghi diversi.
|
||||||
|
|
||||||
|
### Decisione
|
||||||
|
`docs/` sta nel repository del codice e si aggiorna **nella stessa modifica** del codice che la
|
||||||
|
riguarda.
|
||||||
|
|
||||||
|
### Alternative valutate
|
||||||
|
- **Wiki esterno.** Più comodo da modificare, ma non versionato con il codice.
|
||||||
|
|
||||||
|
### Conseguenze
|
||||||
|
- Una revisione del codice è anche revisione della documentazione.
|
||||||
+14
@@ -0,0 +1,14 @@
|
|||||||
|
# DEVELOPMENT LOG — Diario tecnico
|
||||||
|
|
||||||
|
Diario in ordine cronologico inverso. Registra **cosa si è scoperto e perché si è deciso così**,
|
||||||
|
non l'elenco delle modifiche (quello è in [`CHANGELOG.md`](CHANGELOG.md)). Le voci non si
|
||||||
|
cancellano: si annotano.
|
||||||
|
|
||||||
|
Formato del titolo: `## AAAA-MM-GG (n) · titolo che dice cosa si è capito`
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## {{DATA}} · Nasce la documentazione
|
||||||
|
|
||||||
|
Creato lo scheletro della documentazione spec-driven. Decisioni iniziali: `D-001` (stack,
|
||||||
|
proposta), `D-002` (metodo spec-driven), `D-003` (documentazione nel repository).
|
||||||
+43
@@ -0,0 +1,43 @@
|
|||||||
|
# PROJECT MEMORY — Memoria permanente
|
||||||
|
|
||||||
|
Ultimo aggiornamento: **{{DATA}}**
|
||||||
|
|
||||||
|
Da leggere **all'inizio di ogni sessione di lavoro** sul progetto. Contiene ciò che non è
|
||||||
|
deducibile dal codice e che, se dimenticato, fa ripetere errori già commessi. Non è un
|
||||||
|
riassunto della documentazione: ogni voce qui deve avere un perché.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 1. In una frase
|
||||||
|
|
||||||
|
<!-- DA COMPILARE -->
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 2. Le cose da non dimenticare mai
|
||||||
|
|
||||||
|
<!-- Una sottosezione per vincolo. Ogni vincolo dice: la regola, perché esiste (meglio se con
|
||||||
|
un fatto osservato e la data), la decisione D-xxx che la fissa. -->
|
||||||
|
|
||||||
|
### 2.1 <!-- vincolo -->
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 3. Azioni pendenti fuori sequenza
|
||||||
|
|
||||||
|
<!-- DA COMPILARE o «nessuna». Es. credenziali da ruotare. -->
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 4. Metodo
|
||||||
|
|
||||||
|
Spec-driven **vincolante** (D-002): `REQ → SPEC → T → codice + test → TRACEABILITY`.
|
||||||
|
Si implementa solo da una spec *Approvata*.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 5. Come riprendere il lavoro
|
||||||
|
|
||||||
|
1. Leggere questo file e [`../00-INDEX.md`](../00-INDEX.md) (riquadri delle novità in testa).
|
||||||
|
2. Aprire [`TODO.md`](TODO.md): fuori sequenza, poi la fase corrente.
|
||||||
|
3. Per il task scelto: la sua spec, i `REQ` e le `D-xxx` citate.
|
||||||
@@ -0,0 +1,45 @@
|
|||||||
|
# ROADMAP
|
||||||
|
|
||||||
|
Ultimo aggiornamento: **{{DATA}}**
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 0. Fuori sequenza — da fare subito
|
||||||
|
|
||||||
|
| # | Azione | Perché ora |
|
||||||
|
|:-:|---|---|
|
||||||
|
| <!-- DA COMPILARE o «nessuna» --> | | |
|
||||||
|
|
||||||
|
## 1. Fasi
|
||||||
|
|
||||||
|
```
|
||||||
|
┌────────────────────────────────────────────────────────────────────┐
|
||||||
|
│ FASE 0 · Documentazione │
|
||||||
|
│ visione · requisiti · architettura · spec · contratto · dati │
|
||||||
|
│ ▸ criterio di uscita: spec della fase 1 approvate │
|
||||||
|
└────────────────────────────────────────────────────────────────────┘
|
||||||
|
▼
|
||||||
|
┌────────────────────────────────────────────────────────────────────┐
|
||||||
|
│ FASE 1 · Fondamenta │
|
||||||
|
│ <!-- DA COMPILARE --> │
|
||||||
|
│ ▸ criterio di uscita: <!-- DA COMPILARE --> │
|
||||||
|
└────────────────────────────────────────────────────────────────────┘
|
||||||
|
```
|
||||||
|
|
||||||
|
## 2. Dettaglio
|
||||||
|
|
||||||
|
### Fase 1 · Fondamenta
|
||||||
|
|
||||||
|
| Spec | Task | Criterio di uscita |
|
||||||
|
|---|---|---|
|
||||||
|
| <!-- SPEC-001 --> | <!-- T-010…019 --> | |
|
||||||
|
|
||||||
|
## 3. Dipendenze critiche
|
||||||
|
|
||||||
|
<!-- DA COMPILARE -->
|
||||||
|
|
||||||
|
## 4. Rischi
|
||||||
|
|
||||||
|
| Rischio | Fase | Contromisura |
|
||||||
|
|---|---|---|
|
||||||
|
| <!-- DA COMPILARE --> | | |
|
||||||
@@ -0,0 +1,39 @@
|
|||||||
|
# TODO — Backlog
|
||||||
|
|
||||||
|
Ultimo aggiornamento: **{{DATA}}**
|
||||||
|
|
||||||
|
Stato: ⬜ da fare · 🟡 in corso · ✅ fatto · ⏸ sospeso
|
||||||
|
|
||||||
|
**Regola:** un task entra in lavorazione solo se la sua specifica è approvata (D-002). Al termine
|
||||||
|
si aggiorna [`TRACEABILITY.md`](../07-quality/TRACEABILITY.md) — quando il test passa, non quando
|
||||||
|
il codice è scritto.
|
||||||
|
|
||||||
|
**Numerazione:** i task di `SPEC-nnn` usano il blocco `T-nnn0…T-nnn9` (la spec 4 usa i task da
|
||||||
|
40 a 49); oltre il nono si aggiunge un suffisso (`b`, `c`). I task fuori sequenza usano i numeri
|
||||||
|
da 1 a 9.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 🔴 Fuori sequenza — prima di tutto
|
||||||
|
|
||||||
|
| ID | Task | Stato |
|
||||||
|
|---|---|:-:|
|
||||||
|
| <!-- T-001 --> | | ⬜ |
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Fase 0 · Documentazione
|
||||||
|
|
||||||
|
| ID | Task | Spec | Stato |
|
||||||
|
|---|---|---|:-:|
|
||||||
|
| — | Visione, glossario, casi d'uso, requisiti | — | 🟡 |
|
||||||
|
| — | Architettura, modello dati, sicurezza | — | ⬜ |
|
||||||
|
| — | Specifiche della fase 1 approvate | — | ⬜ |
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Fase 1 · Fondamenta
|
||||||
|
|
||||||
|
| ID | Task | Spec | Stato |
|
||||||
|
|---|---|---|:-:|
|
||||||
|
| <!-- T-010 --> | | <!-- SPEC-001 --> | ⬜ |
|
||||||
Reference in New Issue
Block a user