# Analisi tecnica implementativa — Modalita online e sincronizzazione remota per `docs-node`

Data: 2026-06-23  
Repository target: `sophiadeveloper/mcp-servers`  
Ambito principale: `docs-node`  
Deliverable: analisi tecnica completa + roadmap implementativa  
Metodo: skill `skills/mcp-technical-analyst`, entry point `document-first` / analisi multi-sorgente

---

## 1. Sintesi esecutiva

L'evolutiva richiesta e fattibile e coerente con la direzione gia intrapresa da `docs-node`: il server oggi indicizza documentazione Markdown in SQLite locale, espone risorse MCP, gestisce scaffali, tag, relazioni tra scaffali, relazioni tra documenti, correlazione euristica e import/export tramite manifest portabile. La modalita online deve pero essere progettata come una nuova capacita architetturale, non come semplice aggiunta di un parametro `remote_url`.

La soluzione consigliata e trasformare `docs-node` in un componente dual-mode:

1. **nodo locale MCP** compatibile con l'uso attuale via `stdio`;
2. **nodo remoto autorevole** raggiungibile via HTTP/MCP e API di sincronizzazione;
3. **replica locale** capace di sincronizzare scaffali remoti in modalita read-only o read-write;
4. **modalita ibrida** in cui scaffali locali, remoti, pubblicati e replicati convivono nello stesso database senza confondersi.

La parte piu delicata e la sincronizzazione bidirezionale. Gli ID locali autoincrementali oggi usati da SQLite non sono sufficienti per una replica multi-istanza. Serve introdurre UUID stabili globali, versioning per entita, changelog append-only, stato di sync per scaffale/remoto, tombstone per cancellazioni e gestione esplicita dei conflitti.

La roadmap raccomandata e incrementale:

- **Fase 0**: refactor leggero e preparazione schema non distruttiva;
- **Fase 1**: snapshot/manifest V3 con UUID e versioni;
- **Fase 2**: modalita remote read-only e consultazione server centrale;
- **Fase 3**: replica locale read-only;
- **Fase 3.5**: riallineamento additivo post-implementazione su entita sync mancanti, Manifest V3 e documentazione;
- **Fase 4**: pull incrementale basato su changelog;
- **Fase 5**: publish e push read-write con optimistic concurrency;
- **Fase 6**: risoluzione conflitti;
- **Fase 7**: sincronizzazione seamless, stato operativo, retry, UX e hardening.

Stato operativo aggiornato: le Fasi 0, 1, 2 e 3 sono considerate chiuse dalla sequenza di sviluppo gia implementata. La roadmap prosegue quindi da Fase 3.5, senza riscrivere la storia delle migrazioni o delle commit gia pubblicate. La Fase 3.5 e una fase di fixing/allineamento additiva: deve colmare i gap emersi rispetto alla versione aggiornata dell'analisi prima di introdurre changelog, pull incrementale e tombstone attivi in Fase 4.

Non e consigliato implementare subito sync bidirezionale automatico senza versioning e conflitti: il rischio di perdita dati, sovrascritture silenziose e divergenza tra repliche sarebbe alto.

---

## 2. Metodo di analisi e fonti

### 2.1 Skill applicata

La skill `mcp-technical-analyst` dichiara esplicitamente il suo uso per analisi tecniche multi-sorgente, gap analysis, ricostruzione requisiti e deliverable Markdown verificabili. Le sue regole permanenti richiedono di separare evidenza osservata, inferenza e punto aperto, usare percorsi espliciti per artefatti e redigere dati sensibili.

Fonti skill consultate:

- `skills/mcp-technical-analyst/SKILL.md`, righe 4-10: descrizione e trigger della skill.
- `skills/mcp-technical-analyst/SKILL.md`, righe 30-38: regole permanenti.
- `skills/mcp-technical-analyst/references/analysis-workflow.md`, righe 23-35: workflow document-first.
- `skills/mcp-technical-analyst/references/deliverable-templates.md`, righe 44-64: template analisi tecnica finale e regole di scrittura.
- `skills/mcp-technical-analyst/references/source-matrix.md`, righe 50-58: gestione di shelf docs e ricerca mirata.

### 2.2 Regole interne repo applicate

Le regole permanenti del repository richiedono:

- compatibilita legacy salvo istruzioni esplicite contrarie;
- cambi incrementali, una milestone/PR per volta;
- niente refactor estesi fuori scope;
- aggiornamento coerente di codice, test/smoke e documentazione;
- lettura di `RULES.md` locale se presente nella directory target;
- migrazioni versionate non distruttive per storage persistente evolvibile;
- schema MCP compatibili con client severi.

Fonti repo consultate:

- `AGENTS.md`, righe 15-23: priorita operative e regole di compatibilita.
- `AGENTS.md`, righe 32-42: guardrail permanenti MCP/schema/storage.
- `AGENTS.md`, righe 44-53: done minimo per modifiche MCP/skill.
- `docs/mcp-skills-agents-development-guide.md`, righe 20-26: guardrail permanenti.
- `docs/mcp-skills-agents-development-guide.md`, righe 96-102: mappa mentale `docs-node` e manifest V2.
- `docs/mcp-skills-agents-development-guide.md`, righe 103-123: policy tool/resources/artifacts.
- `docs/mcp-runtime-upgrade-governance.md`, righe 36-49: requisiti migrazione storage persistente.

### 2.3 Fonti tecniche `docs-node`

Fonti principali consultate:

- `docs-node/README.md`, righe 3-7: descrizione locale, SQLite e `DOCS_NODE_DB_PATH`.
- `docs-node/README.md`, righe 13-52: schema logico `shelves`, `documents`, `shelf_links`, `document_links`.
- `docs-node/README.md`, righe 56-119: contratti MCP principali per gestione link/correlazione.
- `docs-node/README.md`, righe 123-147: correlazione euristica e manifest V2.
- `docs-node/index.js`, righe 22-29: path database e costante manifest.
- `docs-node/index.js`, righe 185-299 in `initDb()`: creazione tabelle e indici persistenti.
- `docs-node/index.js`, sezione export/import: manifest, ZIP e import transazionale.
- `tests/smoke/docs-node.smoke.mjs`, righe 68-260: smoke MCP per scan, ricerca e resources.

### 2.4 Fonti MCP esterne

La specifica MCP 2025-06-18 definisce due trasporti standard: `stdio` e `Streamable HTTP`. In `Streamable HTTP`, il server opera come processo indipendente, usa endpoint HTTP POST/GET e puo usare SSE per streaming. La specifica richiede inoltre validazione `Origin`, binding localhost per server locali e autenticazione appropriata per connessioni HTTP.  
Fonte: <https://modelcontextprotocol.io/specification/2025-06-18/basic/transports>

La specifica MCP 2025-06-18 considera opzionale l'autorizzazione, ma per trasporti HTTP, quando supportata, raccomanda conformita al flusso di autorizzazione definito, basato su OAuth 2.1 e metadati OAuth.  
Fonte: <https://modelcontextprotocol.io/specification/2025-06-18/basic/authorization>

---

## 3. Requisiti espliciti

Dal requisito utente emergono i seguenti requisiti espliciti:

1. Aggiungere a `docs-node` una **modalita online**.
2. Consentire l'installazione di `docs-node` su un server per **centralizzare la documentazione**.
3. Consentire al `docs-node` locale di puntare a una **fonte remota**, rappresentata da un altro `docs-node` remoto.
4. Supportare import, export e sincronizzazione di:
   - scaffali;
   - tag;
   - mappa mentale;
   - documenti e metadati correlati.
5. Mantenere una **replica locale degli scaffali remoti**.
6. Implementare aggiornamento e sincronizzazione quanto piu possibile **seamless**.
7. Mantenere una sorta di **log modifiche**.
8. Supportare **versioning**.
9. Gestire **conflitti** in caso di modifiche concorrenti.
10. Consentire scaffali locali non pubblicati sul server.
11. Consentire scaffali remoti non replicati o non pubblicati localmente.

---

## 4. Requisiti impliciti e inferiti

Questa sezione contiene inferenze tecniche, non evidenze dirette.

### 4.1 Identita globale

Per sincronizzare entita tra piu istanze, gli ID SQLite autoincrementali non bastano. Occorre introdurre UUID stabili per ogni entita sincronizzabile.

Entita che richiedono UUID:

- shelf;
- document;
- tag;
- relazione shelf-shelf (`shelf_links`);
- relazione document-document (`document_links`);
- assegnazione document-tag (`document_tags`);
- scan source (`scan_sources`), almeno come entita locale/replica;
- change log entry;
- remote source;
- conflict.

Nota correttiva: le relazioni molti-a-molti gia esistenti in `docs-node` non possono restare identificate solo dalle chiavi locali SQLite se devono partecipare a delta sync, tombstone e risoluzione conflitti. Dove si mantiene una chiave composta legacy, serve comunque un UUID tecnico o una chiave canonica stabile serializzata nel changelog. La soluzione piu lineare per questa roadmap e aggiungere UUID/versione/tombstone anche a `shelf_links`, `document_links`, `document_tags` e `scan_sources`.

### 4.2 Versioning per entita

Serve versioning incrementale per determinare se una modifica locale parte da una base ancora valida o se nel frattempo il server remoto ha ricevuto un cambiamento concorrente.

Il versioning deve essere almeno per:

- contenuto documento;
- metadati documento;
- nome/descrizione shelf;
- tag dictionary;
- assegnazioni tag;
- link manuali della mappa mentale;
- link euristici se pubblicati o sincronizzati.

### 4.3 Separazione dati utente e cache rigenerabile

Le cache FTS e gli indici locali sono rigenerabili; contenuti, tag, link manuali, decisioni di conflitto e change log non lo sono. La governance runtime richiede di distinguere cache rigenerabili da dati utente non rigenerabili.

### 4.4 Scaffale come unita primaria di sincronizzazione

Lo scaffale deve essere l'unita principale di sync per coerenza funzionale. Sincronizzare singoli documenti senza il contesto di shelf, tag dictionary e mappa mentale produrrebbe stati parziali difficili da ragionare.

### 4.5 Remote source come entita configurabile

Un nodo locale puo puntare a uno o piu server remoti. Serve una tabella `remote_sources` e non un singolo `DOCS_NODE_REMOTE_URL` globale.

---

## 5. Stato dell'arte di `docs-node`

### 5.1 Evidenze osservate

`docs-node` e oggi un server MCP locale Node.js/JavaScript che usa SQLite. Il database predefinito e `docs-node/docs.db`, con override tramite `DOCS_NODE_DB_PATH`.

Lo schema documentato comprende:

- `shelves`;
- `documents`;
- `shelf_links`;
- `document_links`.

Nel codice runtime sono presenti anche:

- `tags`;
- `document_tags`;
- `scan_sources`;
- `feature_state`;
- indici FTS5 `documents_fts` se disponibili;
- fallback LIKE se FTS5 non e disponibile.

Gli handler MCP espongono:

- `docs_management` per scan, gestione scaffali, tag, import/export, relazioni e correlazione;
- `docs_navigation` per ricerca, lettura e lista documenti;
- resources `docs://shelf/...` e `docs://document/...`.

Il test smoke copre almeno:

- avvio server con DB temporaneo;
- `scan_file`;
- `list_documents`;
- ricerca full-text con query problematiche;
- `resources/list`;
- `resources/read` per shelf;
- verifica URI `docs://document/...`.

### 5.2 Cosa e gia pronto per l'evolutiva

Punti favorevoli:

1. **Storage SQLite gia strutturato**: e semplice aggiungere tabelle di sync, changelog e conflitti.
2. **Pattern di upgrade idempotente**: il codice crea tabelle e indici se non esistono.
3. **Risorse MCP gia presenti**: i documenti sono gia navigabili via URI.
4. **Manifest V2 gia portabile**: export/import non dipendono dagli ID locali per i link, ma da path relativi.
5. **Mappa mentale gia modellata**: `shelf_links` e `document_links` sono gia concetti sincronizzabili.
6. **Test smoke esistente**: base minima da estendere.

### 5.3 Gap principali

1. **Assenza di UUID globali**: oggi l'identita pubblica e basata su ID locali.
2. **Assenza di schema migrations versionate**: il pattern e idempotente, ma la governance chiede schema versionato per storage evolvibile.
3. **Assenza di changelog append-only**: non e possibile fare delta sync robusto.
4. **Assenza di conflitti persistiti**: l'import usa `fail`, `merge`, `replace`, ma non una risoluzione conflitti concorrente.
5. **Assenza di remote source model**: non esiste configurazione multi-remoto.
6. **Assenza di transport HTTP MCP**: oggi il server e orientato a `stdio` locale.
7. **Assenza di authorization/ACL**: requisito imprescindibile per server centralizzato.
8. **Assenza di distinzione ufficiale tra locale, pubblicato, replicato e remoto-only**.

---

## 6. Architettura target proposta

### 6.1 Visione logica

```text
+----------------------+        HTTPS/MCP + Sync API        +----------------------+
| docs-node locale     | <------------------------------->  | docs-node remoto     |
|                      |                                    |                      |
| - MCP stdio          |                                    | - MCP HTTP           |
| - SQLite locale      |                                    | - SQLite/Postgres*   |
| - FTS locale         |                                    | - Auth/ACL           |
| - replica scaffali   |                                    | - changelog globale  |
| - scaffali privati   |                                    | - snapshot/delta     |
+----------------------+                                    +----------------------+

* Prima versione: SQLite server-side. Postgres e una possibile evoluzione, non prerequisito.
```

### 6.2 Ruoli nodo

Il processo `docs-node` dovrebbe supportare un parametro/modalita di avvio:

```text
DOCS_NODE_MODE=local | remote-server | local-replica | hybrid
```

Oppure una CLI:

```bash
node docs-node/index.js --mode local
node docs-node/index.js --mode remote-server --http-port 8732
node docs-node/index.js --mode hybrid
```

#### `local`

Modalita attuale. Nessun comportamento remoto implicito.

#### `remote-server`

Nodo autorevole su server:

- espone MCP Streamable HTTP;
- espone API sync;
- gestisce autenticazione;
- applica ACL per shelf;
- registra changelog;
- mantiene snapshot e delta.

#### `local-replica`

Nodo locale con replica di scaffali remoti:

- pull/push verso server;
- cache FTS locale;
- conflitti locali consultabili;
- modalita offline parziale.

#### `hybrid`

Modalita consigliata come default evolutivo locale:

- mantiene compatibilita locale;
- consente scaffali privati;
- consente scaffali remoti read-only;
- consente scaffali pubblicati read-write;
- consente consultazione remota senza replica completa.

### 6.3 Separazione moduli

Il file `docs-node/index.js` oggi e molto carico. Per evitare refactor monolitico, procedere per estrazione incrementale.

Struttura target:

```text
docs-node/
  index.js
  package.json
  src/
    db/
      connection.js
      migrations.js
      schema.js
    core/
      shelves.js
      documents.js
      tags.js
      links.js
      import-export.js
      resources.js
      search.js
      correlate.js
    sync/
      identity.js
      changelog.js
      snapshot.js
      delta.js
      conflicts.js
      remote-client.js
      remote-server-api.js
    transports/
      stdio-mcp.js
      http-mcp.js
    security/
      auth.js
      acl.js
      redaction.js
    tools/
      docs-management.js
      docs-navigation.js
      docs-remote.js
```

Prima milestone: non serve spostare tutto. Basta isolare nuovi moduli `sync/*`, `security/*` e `transports/http-mcp.js` lasciando il core esistente al suo posto.

---

## 7. Modello dati target

### 7.1 Principi

1. Ogni entita sincronizzabile ha un UUID stabile.
2. Ogni entita ha una versione logica incrementale.
3. A regime, ogni modifica persistente sincronizzabile genera una entry di changelog.
4. Le cancellazioni sincronizzabili usano tombstone, non delete fisico immediato.
5. I conflitti sono entita persistenti, non solo errori runtime.
6. Le cache rigenerabili sono separate dal dato utente.

### 7.2 Nuove colonne identita/versione

Migrazione proposta:

```sql
ALTER TABLE shelves ADD COLUMN uuid TEXT;
ALTER TABLE shelves ADD COLUMN version INTEGER NOT NULL DEFAULT 1;
ALTER TABLE shelves ADD COLUMN visibility TEXT NOT NULL DEFAULT 'local_only';
ALTER TABLE shelves ADD COLUMN deleted_at TEXT;
ALTER TABLE shelves ADD COLUMN last_synced_at TEXT;

ALTER TABLE documents ADD COLUMN uuid TEXT;
ALTER TABLE documents ADD COLUMN version INTEGER NOT NULL DEFAULT 1;
ALTER TABLE documents ADD COLUMN content_sha256 TEXT;
ALTER TABLE documents ADD COLUMN metadata_sha256 TEXT;
ALTER TABLE documents ADD COLUMN deleted_at TEXT;
ALTER TABLE documents ADD COLUMN remote_origin_uuid TEXT;

ALTER TABLE tags ADD COLUMN uuid TEXT;
ALTER TABLE tags ADD COLUMN version INTEGER NOT NULL DEFAULT 1;
ALTER TABLE tags ADD COLUMN deleted_at TEXT;

ALTER TABLE document_links ADD COLUMN uuid TEXT;
ALTER TABLE document_links ADD COLUMN version INTEGER NOT NULL DEFAULT 1;
ALTER TABLE document_links ADD COLUMN deleted_at TEXT;

ALTER TABLE shelf_links ADD COLUMN uuid TEXT;
ALTER TABLE shelf_links ADD COLUMN version INTEGER NOT NULL DEFAULT 1;
ALTER TABLE shelf_links ADD COLUMN deleted_at TEXT;

ALTER TABLE document_tags ADD COLUMN uuid TEXT;
ALTER TABLE document_tags ADD COLUMN version INTEGER NOT NULL DEFAULT 1;
ALTER TABLE document_tags ADD COLUMN deleted_at TEXT;

ALTER TABLE scan_sources ADD COLUMN uuid TEXT;
ALTER TABLE scan_sources ADD COLUMN version INTEGER NOT NULL DEFAULT 1;
ALTER TABLE scan_sources ADD COLUMN deleted_at TEXT;
```

Nota: SQLite non consente sempre aggiunte con vincoli complessi in modo semplice. La migrazione deve aggiungere colonne nullable, popolarle, poi creare indici unici parziali dove supportato.

Nota operativa: l'aggiunta di `version`, `content_sha256` e `metadata_sha256` non basta se i write path continuano ad aggiornare solo i campi legacy. La stessa fase che introduce questi campi deve anche aggiornare i percorsi di scrittura principali (`scan_file`, `scan_folder`, tag, link, import, remove) per mantenere versioni e hash coerenti, almeno senza generare ancora un changelog pubblico.

### 7.2.1 Tombstone e compatibilita legacy

Fase 0 deve predisporre `deleted_at`, ma non deve cambiare automaticamente la semantica legacy di `remove_shelf` e `remove_document`: oggi queste azioni fanno delete fisico e i client esistenti si aspettano la sparizione immediata dai risultati.

Il passaggio operativo a soft delete/tombstone deve avvenire quando viene introdotto il changelog incrementale, quindi in Fase 4, con filtri espliciti su tutte le query di lettura e test dedicati. Prima di quella fase:

- `deleted_at` resta una colonna di predisposizione e backfill;
- Manifest V3 esporta solo entita attive, salvo modalita diagnostica esplicita;
- le cancellazioni locali legacy non sono ancora sincronizzabili come tombstone;
- la documentazione deve dichiarare chiaramente questa limitazione temporanea.

### 7.3 Nuova tabella `node_identity`

```sql
CREATE TABLE IF NOT EXISTS node_identity (
  id INTEGER PRIMARY KEY CHECK (id = 1),
  node_uuid TEXT NOT NULL UNIQUE,
  node_name TEXT,
  created_at TEXT NOT NULL DEFAULT (datetime('now')),
  updated_at TEXT NOT NULL DEFAULT (datetime('now'))
);
```

Uso:

- distinguere cambi locali da cambi remoti;
- evitare loop di sync;
- attribuire origine changelog.

### 7.4 Nuova tabella `remote_sources`

```sql
CREATE TABLE IF NOT EXISTS remote_sources (
  id INTEGER PRIMARY KEY AUTOINCREMENT,
  uuid TEXT NOT NULL UNIQUE,
  name TEXT NOT NULL,
  base_url TEXT NOT NULL UNIQUE,
  auth_profile TEXT,
  trust_level TEXT NOT NULL DEFAULT 'internal',
  created_at TEXT NOT NULL DEFAULT (datetime('now')),
  updated_at TEXT NOT NULL DEFAULT (datetime('now'))
);
```

`auth_profile` non deve contenere token in chiaro. Deve puntare a meccanismo sicuro: env var, secret store OS, file locale protetto o configurazione client.

### 7.5 Nuova tabella `shelf_sync_state`

```sql
CREATE TABLE IF NOT EXISTS shelf_sync_state (
  shelf_uuid TEXT NOT NULL,
  remote_source_uuid TEXT NOT NULL,
  remote_shelf_uuid TEXT NOT NULL,
  sync_mode TEXT NOT NULL,
  last_pulled_cursor TEXT,
  last_pushed_cursor TEXT,
  last_successful_sync_at TEXT,
  last_attempt_at TEXT,
  status TEXT NOT NULL DEFAULT 'never_synced',
  error_json TEXT,
  PRIMARY KEY (shelf_uuid, remote_source_uuid),
  CHECK(sync_mode IN ('read_only', 'read_write', 'push_only', 'pull_only'))
);
```

### 7.6 Nuova tabella `change_log`

```sql
CREATE TABLE IF NOT EXISTS change_log (
  id INTEGER PRIMARY KEY AUTOINCREMENT,
  change_uuid TEXT NOT NULL UNIQUE,
  node_uuid TEXT NOT NULL,
  actor_id TEXT,
  shelf_uuid TEXT,
  entity_type TEXT NOT NULL,
  entity_uuid TEXT NOT NULL,
  operation TEXT NOT NULL,
  base_version INTEGER,
  new_version INTEGER,
  base_hash TEXT,
  new_hash TEXT,
  payload_json TEXT NOT NULL,
  created_at TEXT NOT NULL DEFAULT (datetime('now')),
  pushed_at TEXT,
  pulled_from_remote_uuid TEXT,
  applied_at TEXT,
  rejected_at TEXT,
  rejection_reason TEXT
);

CREATE INDEX IF NOT EXISTS idx_change_log_shelf_id ON change_log(shelf_uuid, id);
CREATE INDEX IF NOT EXISTS idx_change_log_entity ON change_log(entity_type, entity_uuid);
CREATE INDEX IF NOT EXISTS idx_change_log_created ON change_log(created_at);
```

Operazioni iniziali:

```text
shelf.create
shelf.update
shelf.delete
shelf.restore

document.create
document.update_content
document.update_metadata
document.move
document.delete
document.restore

tag.create
tag.update
tag.delete

document_tag.add
document_tag.remove

shelf_link.add
shelf_link.remove

document_link.add
document_link.update
document_link.remove

scan_source.add
scan_source.update
scan_source.remove
```

### 7.7 Nuova tabella `sync_conflicts`

```sql
CREATE TABLE IF NOT EXISTS sync_conflicts (
  id INTEGER PRIMARY KEY AUTOINCREMENT,
  conflict_uuid TEXT NOT NULL UNIQUE,
  shelf_uuid TEXT NOT NULL,
  remote_source_uuid TEXT,
  entity_type TEXT NOT NULL,
  entity_uuid TEXT NOT NULL,
  local_change_uuid TEXT,
  remote_change_uuid TEXT,
  base_version INTEGER,
  local_version INTEGER,
  remote_version INTEGER,
  base_payload_json TEXT,
  local_payload_json TEXT,
  remote_payload_json TEXT,
  status TEXT NOT NULL DEFAULT 'open',
  resolution TEXT,
  resolved_payload_json TEXT,
  created_at TEXT NOT NULL DEFAULT (datetime('now')),
  resolved_at TEXT,
  CHECK(status IN ('open', 'resolved', 'ignored'))
);
```

### 7.8 Tabelle aus evitare nella prima fase

Non introdurre subito CRDT complessi o branch per documento. Per il requisito attuale basta optimistic concurrency + changelog + conflitti espliciti.

---

## 8. Manifest V3 per snapshot e portabilita

### 8.1 Perche serve V3

Il manifest V2 risolve la portabilita dei link tramite `relative_path`, ma non contiene identita globale, versioning, tombstone, cursori o provenienza remota. Per la sincronizzazione serve un manifest V3 retrocompatibile.

### 8.2 Schema logico V3

```json
{
  "meta": {
    "format_version": 3,
    "exported_at": "2026-06-23T00:00:00.000Z",
    "exported_by_node_uuid": "...",
    "mode": "snapshot",
    "common_root": "...",
    "includes_files": true,
    "includes_changelog": false
  },
  "shelf": {
    "uuid": "...",
    "name": "Framework Standard",
    "description": "...",
    "version": 12,
    "visibility": "published"
  },
  "tags_dictionary": [
    {
      "uuid": "...",
      "name": "auth",
      "description": "Autenticazione",
      "version": 3,
      "deleted_at": null
    }
  ],
  "scan_sources": [
    {
      "uuid": "...",
      "source_ref": "source-1",
      "source_type": "folder",
      "relative_path": ".",
      "recursive": true,
      "version": 1,
      "deleted_at": null
    }
  ],
  "documents": [
    {
      "uuid": "...",
      "relative_path": "guide/setup.md",
      "title": "Setup",
      "version": 4,
      "content_sha256": "...",
      "metadata_sha256": "...",
      "source_ref": "source-1",
      "tags": ["auth", "setup"],
      "deleted_at": null,
      "bundle_file": "files/guide/setup.md"
    }
  ],
  "document_tags": [
    {
      "uuid": "...",
      "document_uuid": "...",
      "document_relative_path": "guide/setup.md",
      "tag_uuid": "...",
      "tag_name": "auth",
      "version": 1,
      "deleted_at": null
    }
  ],
  "shelf_links": [
    {
      "uuid": "...",
      "parent_shelf_uuid": "...",
      "parent_shelf_name": "Framework Standard",
      "child_shelf_uuid": "...",
      "child_shelf_name": "Cliente X",
      "relation": "parent",
      "version": 1,
      "deleted_at": null
    }
  ],
  "document_links": [
    {
      "uuid": "...",
      "source_document_uuid": "...",
      "target_document_uuid": "...",
      "source_relative_path": "cliente/login.md",
      "target_relative_path": "standard/auth.md",
      "relation": "references_standard",
      "origin": "manual",
      "confidence": 1.0,
      "label": "...",
      "rationale": "...",
      "version": 2,
      "deleted_at": null
    }
  ]
}
```

In V3 `documents[].tags` puo restare come comodita retrocompatibile e leggibile, ma la fonte autorevole per sync, delta e conflitti delle assegnazioni tag deve essere `document_tags[]`, perche contiene UUID, versione e tombstone dell'assegnazione.

### 8.3 Compatibilita V2

`import_shelf` deve continuare ad accettare manifest V1/V2. Per V1/V2:

- generare UUID locali mancanti;
- importare con `visibility='local_only'` salvo parametro esplicito;
- generare `version=1`;
- calcolare `content_sha256`;
- non creare stato remoto.

---

## 9. API di sincronizzazione

### 9.1 Perche non usare solo tool MCP

MCP e ideale per consultazione e automazione da parte degli agenti. La replica richiede pero:

- cursori;
- batch idempotenti;
- retry;
- codici errore HTTP precisi;
- paginazione;
- upload/download snapshot;
- autenticazione e autorizzazione a livello trasporto;
- transazioni server-side.

Quindi conviene affiancare al transport MCP una API HTTP dedicata alla sync.

### 9.2 Endpoint server minimi

```text
GET  /health
GET  /sync/remotes/self
GET  /sync/shelves
GET  /sync/shelves/{shelf_uuid}
GET  /sync/shelves/{shelf_uuid}/snapshot
GET  /sync/shelves/{shelf_uuid}/changes?since={cursor}&limit={n}
POST /sync/shelves/{shelf_uuid}/changes
POST /sync/shelves/{shelf_uuid}/publish
POST /sync/conflicts/{conflict_uuid}/resolve
```

### 9.3 Pull delta

Richiesta:

```http
GET /sync/shelves/{shelf_uuid}/changes?since=chg_000123&limit=500
Authorization: Bearer ...
```

Risposta:

```json
{
  "ok": true,
  "shelf_uuid": "...",
  "from_cursor": "chg_000123",
  "next_cursor": "chg_000456",
  "has_more": false,
  "changes": [
    {
      "change_uuid": "...",
      "node_uuid": "remote-node",
      "entity_type": "document",
      "entity_uuid": "...",
      "operation": "document.update_content",
      "base_version": 3,
      "new_version": 4,
      "base_hash": "...",
      "new_hash": "...",
      "payload": {}
    }
  ]
}
```

### 9.4 Push delta

Richiesta:

```http
POST /sync/shelves/{shelf_uuid}/changes
Authorization: Bearer ...
Content-Type: application/json
```

```json
{
  "client_node_uuid": "...",
  "changes": [
    {
      "change_uuid": "...",
      "entity_type": "document",
      "entity_uuid": "...",
      "operation": "document.update_content",
      "base_version": 4,
      "new_version": 5,
      "base_hash": "...",
      "new_hash": "...",
      "payload": {}
    }
  ]
}
```

Risposta:

```json
{
  "ok": true,
  "accepted": ["..."],
  "conflicts": [],
  "rejected": []
}
```

Se conflitto:

```json
{
  "ok": false,
  "accepted": [],
  "conflicts": [
    {
      "conflict_uuid": "...",
      "entity_type": "document",
      "entity_uuid": "...",
      "reason": "remote_version_changed",
      "base_version": 4,
      "local_version": 5,
      "remote_version": 6
    }
  ]
}
```

---

## 10. Tool MCP da aggiungere

### 10.1 Nuovo tool `docs_remote`

Per compatibilita e chiarezza, non sovraccaricare `docs_management`. Aggiungere un tool separato:

```text
docs_remote
```

Descrizione breve, compatibile con token diet:

```text
Configura fonti docs remote e sincronizza scaffali pubblicati o replicati.
```

### 10.2 Azioni proposte

#### `configure_remote`

```json
{
  "action": "configure_remote",
  "name": "docs-prod",
  "base_url": "https://docs.example.com/mcp",
  "auth_profile": "DOCS_NODE_TOKEN"
}
```

#### `list_remotes`

```json
{
  "action": "list_remotes"
}
```

#### `list_remote_shelves`

```json
{
  "action": "list_remote_shelves",
  "remote": "docs-prod"
}
```

#### `subscribe_shelf`

```json
{
  "action": "subscribe_shelf",
  "remote": "docs-prod",
  "remote_shelf_uuid": "...",
  "local_name": "Framework Standard",
  "sync_mode": "read_only",
  "replicate_files": true
}
```

#### `publish_shelf`

```json
{
  "action": "publish_shelf",
  "shelf": "Framework Standard",
  "remote": "docs-prod",
  "sync_mode": "read_write",
  "include_files": true,
  "dry_run": true
}
```

#### `sync_shelf`

```json
{
  "action": "sync_shelf",
  "shelf": "Framework Standard",
  "direction": "pull_push",
  "dry_run": false
}
```

#### `sync_status`

```json
{
  "action": "sync_status",
  "shelf": "Framework Standard",
  "include_conflicts": true
}
```

#### `list_conflicts`

```json
{
  "action": "list_conflicts",
  "shelf": "Framework Standard",
  "status": "open"
}
```

#### `resolve_conflict`

```json
{
  "action": "resolve_conflict",
  "conflict_uuid": "...",
  "resolution": "use_local"
}
```

Valori `resolution` iniziali:

```text
use_local
use_remote
manual_merge
discard_local
rename_local
keep_both
```

### 10.3 Aggiornamento `docs_management`

Aggiungere solo parametri mirati:

- `visibility` su `create_shelf` / `update_shelf`;
- `remote_policy` su `remove_shelf` per impedire delete accidentali di scaffali replicati;
- `generate_change_log` interno, non necessariamente esposto.

### 10.4 Aggiornamento `docs_navigation`

Aggiungere campi opzionali nei risultati:

```json
{
  "sync": {
    "visibility": "replicated_read_only",
    "remote": "docs-prod",
    "last_synced_at": "...",
    "has_conflicts": false
  }
}
```

Per documenti con conflitti aperti, `read_document` dovrebbe mostrare warning strutturato, non solo testo libero.

---

## 11. Transport HTTP MCP

### 11.1 Scelta consigliata

Implementare `Streamable HTTP` come transport MCP per il nodo remoto, mantenendo `stdio` per il nodo locale.

Motivazione:

- `stdio` resta il percorso piu semplice per client locali;
- `Streamable HTTP` e il transport standard per server indipendenti e multi-client;
- consente autenticazione, deployment server e accesso remoto.

### 11.2 Endpoint MCP

Esempio:

```text
POST /mcp
GET  /mcp
DELETE /mcp
```

Requisiti:

- supportare `MCP-Protocol-Version`;
- validare `Origin`;
- autenticare ogni richiesta;
- non scrivere segreti nei log;
- usare session ID sicuri se si mantiene stato di sessione;
- prevedere fallback o documentazione se client non supporta HTTP MCP.

### 11.3 Dipendenze Node

Possibili dipendenze:

- `express` o server HTTP nativo;
- middleware auth minimale;
- eventuale libreria SSE.

Dato che `package.json` oggi dipende da `@modelcontextprotocol/sdk`, `jszip` e `sqlite3`, ogni nuova dipendenza deve aggiornare documentazione e richiedere rilancio setup secondo governance.

---

## 12. Sicurezza e autorizzazione

### 12.1 Requisiti minimi server remoto

1. HTTPS obbligatorio in produzione.
2. Token bearer o OAuth/JWT.
3. ACL per shelf.
4. Separazione ruoli read/write/admin.
5. Audit `actor_id` su changelog.
6. Rate limit.
7. Validazione `Origin`.
8. Nessun token in DB in chiaro.
9. Redazione segreti nei deliverable e log.
10. CORS allowlist esplicita.

### 12.2 Scopes consigliati

```text
docs:read
docs:write
docs:admin
shelf:read:{uuid}
shelf:write:{uuid}
shelf:publish
conflict:resolve
```

### 12.3 ACL dati

Tabella:

```sql
CREATE TABLE IF NOT EXISTS shelf_acl (
  id INTEGER PRIMARY KEY AUTOINCREMENT,
  shelf_uuid TEXT NOT NULL,
  subject_type TEXT NOT NULL,
  subject_id TEXT NOT NULL,
  role TEXT NOT NULL,
  created_at TEXT NOT NULL DEFAULT (datetime('now')),
  UNIQUE(shelf_uuid, subject_type, subject_id, role)
);
```

Ruoli:

```text
reader
writer
maintainer
admin
```

### 12.4 Rischi MCP specifici

La documentazione indicizzata puo contenere istruzioni malevole o testo non fidato. Quando il nodo remoto serve documenti ad agenti, occorre evitare che contenuti documentali vengano trattati come istruzioni di sistema. Questa e una policy di consumo lato agente/client, ma il server puo aiutare con metadati:

```json
{
  "content_trust": "documentation_user_content",
  "contains_executable_instructions": false,
  "source": "remote-docs-node"
}
```

---

## 13. Gestione conflitti

### 13.1 Principio base

Usare optimistic concurrency:

- ogni client modifica una base nota (`base_version`, `base_hash`);
- il server accetta solo se la versione remota corrente coincide;
- altrimenti crea conflitto.

### 13.2 Matrice conflitti

| Entita | Tipo modifica | Strategia automatica | Quando aprire conflitto |
|---|---|---|---|
| Shelf | rename | no | sempre se remoto diverso |
| Shelf | descrizione | last-write opzionale | se entrambi modificano |
| Document | contenuto | 3-way merge tentativo | stessa sezione modificata |
| Document | titolo | no | se divergente |
| Document | path | no | se divergente |
| Tag | create | merge per nome/uuid | nome duplicato con uuid diverso |
| Tag | rename | no | se rinominato in modo diverso |
| document_tags | add/remove | OR-Set semplice | add/remove concorrente stesso tag |
| shelf_links | add/remove | set merge con tombstone | remove vs update concorrente |
| document_links manual | update | no | sempre se concorrente |
| document_links heuristic | update | rigenera o remote wins | raramente, se pubblicati |

### 13.3 Merge documenti Markdown

Per `document.update_content`:

1. recuperare base, local, remote;
2. provare merge 3-way testuale;
3. se merge pulito, creare nuova versione;
4. se conflitto, salvare payload triplo in `sync_conflicts`;
5. esporre conflitto in `docs_remote list_conflicts`.

Non inserire marker Git-style direttamente nel documento indicizzato salvo scelta esplicita. Meglio salvare conflitto separato e lasciare il documento nella versione sicura.

### 13.4 Heuristic links

I link `origin='heuristic'` sono rigenerabili e non dovrebbero bloccare una sincronizzazione. Regola consigliata:

- i link manuali prevalgono sempre;
- i link euristici locali non devono sovrascrivere link manuali remoti;
- i link euristici con confidenza bassa possono essere esclusi dal push;
- i link euristici possono essere marcati con `heuristic_version` e rigenerati post-sync.

---

## 14. Flussi utente

### 14.1 Configurare un server remoto

```text
1. Admin installa docs-node su server.
2. Avvia in mode=remote-server.
3. Configura HTTPS/reverse proxy.
4. Configura token/OAuth.
5. Pubblica endpoint /mcp e /sync.
6. Client locale esegue docs_remote configure_remote.
```

### 14.2 Pubblicare uno scaffale locale

```text
1. Utente ha shelf locale `Framework Standard`.
2. Esegue publish_shelf dry_run=true.
3. docs-node calcola snapshot, UUID mancanti, impatto remoto.
4. Utente riesegue dry_run=false.
5. Server crea shelf remoto e stato sync.
6. Locale passa a visibility=published.
```

### 14.3 Sottoscrivere uno scaffale remoto

```text
1. Utente lista scaffali remoti.
2. Seleziona remote_shelf_uuid.
3. subscribe_shelf crea record locale.
4. Scarica snapshot V3.
5. Indicizza FTS locale.
6. Stato diventa replicated_read_only o replicated_read_write.
```

### 14.4 Sincronizzazione manuale

```text
1. sync_shelf direction=pull_push dry_run=true.
2. Mostra changes inbound/outbound e conflitti previsti.
3. sync_shelf dry_run=false.
4. Applica pull, poi push o viceversa secondo policy.
5. Aggiorna cursor e stato.
```

Sequenza consigliata per read-write:

```text
pull -> risolvi conflitti -> push
```

### 14.5 Scaffali locali non pubblicati

Default: ogni nuovo shelf rimane `local_only`.

Nessun sync automatico senza `publish_shelf` o `subscribe_shelf`.

### 14.6 Scaffali remoti non replicati

`list_remote_shelves` deve poter mostrare shelf disponibili senza crearne copia locale. `docs_navigation` potrebbe in futuro fare proxy read-through, ma non e necessario in prima release.

---

## 15. Migrazioni e upgrade path

### 15.1 Problema attuale

`docs-node` usa creazione idempotente tabelle/indici. Questo e utile, ma l'evolutiva sync introduce stato persistente sensibile. La governance runtime richiede tabella di versionamento schema, baseline legacy, migrazioni ordinate, transazionali e test su stato vuoto/legacy.

### 15.2 Tabella `schema_migrations`

```sql
CREATE TABLE IF NOT EXISTS schema_migrations (
  version INTEGER PRIMARY KEY,
  name TEXT NOT NULL,
  applied_at TEXT NOT NULL
);
```

### 15.3 Migrazioni proposte

```text
001_baseline_existing_docs_node
002_add_uuid_and_version_columns
003_backfill_uuids_hashes_versions
004_add_write_metadata_maintenance
005_add_remote_sources_and_sync_state
006_add_change_log
007_add_sync_conflicts
008_add_acl_remote_server
009_add_manifest_v3_support
```

Nota post-Fase 3: questa numerazione resta una sequenza logica ideale della roadmap. Poiche le Fasi 0-3 sono gia state implementate, la Fase 3.5 non deve rinumerare migrazioni esistenti: deve aggiungere una o piu migrazioni forward-only successive alla versione corrente per colmare `document_tags`, `scan_sources`, `visibility` e Manifest V3.

### 15.4 Baseline legacy

All'avvio:

1. aprire SQLite;
2. creare `schema_migrations` se manca;
3. rilevare se esistono tabelle legacy;
4. registrare baseline `001` senza distruggere dati;
5. applicare migrazioni successive in transazione;
6. solo dopo registrare handler MCP.

### 15.5 Backfill UUID

Per ogni entita esistente:

```text
shelves.uuid = randomUUID()
documents.uuid = randomUUID()
tags.uuid = randomUUID()
document_links.uuid = randomUUID()
```

Per hash contenuto:

```text
documents.content_sha256 = sha256(content)
```

### 15.6 Rollback

Non prevedere rollback automatico distruttivo. In caso errore:

- transazione rollback;
- messaggio MCP chiaro;
- indicare path DB;
- consigliare backup;
- non avviare tool write-capable.

---

## 16. Strategia implementativa incrementale

### 16.1 Principi di delivery

Seguire le regole repo:

- una milestone/PR per volta;
- compatibilita legacy;
- nessun refactor massivo fuori scope;
- test smoke/schema per ogni modifica;
- documentazione aggiornata;
- restart server MCP dopo update.

### 16.2 Roadmap dettagliata

#### Fase 0 — Preparazione schema e refactor minimo

Obiettivo: rendere `docs-node` pronto al sync senza cambiare comportamento utente.

Deliverable:

- introdurre `schema_migrations`;
- aggiungere UUID/version/hash e predisposizione `deleted_at` alle entita sincronizzabili principali, incluse relazioni e assegnazioni (`shelf_links`, `document_links`, `document_tags`, `scan_sources`);
- backfill non distruttivo;
- helper `ensureEntityUuid`;
- helper `computeDocumentHashes`;
- aggiornamento minimo dei write path per mantenere `version`, `content_sha256` e `metadata_sha256` coerenti;
- test migration su DB vuoto e fixture legacy;
- README aggiornato;
- aggiornamento `docs/server-capability-matrix.md` per dichiarare storage versionato e upgrade path.

Criteri accettazione:

- smoke esistente passa invariato;
- DB legacy viene migrato senza perdita dati;
- `docs_management list_shelves` continua a funzionare;
- `docs_navigation read_document` continua a usare ID legacy;
- nuove URI UUID disponibili ma non obbligatorie.
- i write path principali aggiornano version/hash senza cambiare l'output legacy.

Rischio: medio, per modifica storage persistente.

#### Fase 1 — Manifest V3 e snapshot locale

Obiettivo: introdurre snapshot portabile con UUID/versioni.

Deliverable:

- `DOCS_EXPORT_FORMAT_VERSION = 3` per nuovi export, mantenendo import V1/V2;
- `export_shelf` con `format_version` selezionabile o default V3;
- `import_shelf` idempotente su UUID;
- supporto `visibility`;
- test export/import V2 backward e V3 roundtrip.

Criteri accettazione:

- import V2 esistenti ancora funzionanti;
- export V3 reimportato non duplica entita se UUID combaciano;
- link documentali risolti via UUID con fallback relative path;
- version/hash inclusi nel manifest derivano da campi mantenuti dai write path, non solo da backfill iniziale.

Rischio: medio.

#### Fase 2 — Remote server read-only

Obiettivo: servire documentazione centralizzata senza push.

Deliverable:

- modalita `remote-server`;
- transport MCP HTTP su `/mcp`;
- endpoint `/health`;
- endpoint `/sync/shelves` e `/sync/shelves/{uuid}/snapshot`;
- auth bearer token minimale;
- validazione `Origin` configurabile;
- docs di deployment.

Criteri accettazione:

- `stdio` locale invariato;
- server remoto lista scaffali;
- client autorizzato scarica snapshot;
- richiesta non autorizzata riceve 401/403;
- nessun token nei log.

Rischio: medio-alto, per sicurezza/transport.

#### Fase 3 — Replica locale read-only

Obiettivo: permettere a un `docs-node` locale di mantenere copia locale di scaffali remoti.

Deliverable:

- tabella `remote_sources`;
- tabella `shelf_sync_state`;
- tool `docs_remote` con `configure_remote`, `list_remote_shelves`, `subscribe_shelf`, `sync_status`;
- import snapshot da remoto;
- aggiornamento FTS locale;
- blocco modifiche write su shelf read-only replicati.

Criteri accettazione:

- shelf remoto replicato consultabile offline;
- `docs_navigation search` funziona sulla replica;
- modifiche write su replica read-only falliscono con errore chiaro;
- `sync_status` mostra ultimo pull.

Rischio: medio.

#### Fase 3.5 — Riallineamento post-Fase 3

Obiettivo: allineare lo sviluppo gia completato fino alla replica read-only con la versione aggiornata dell'analisi, prima di introdurre changelog e pull incrementale.

Premessa operativa:

- Fase 0, Fase 1, Fase 2 e Fase 3 sono considerate chiuse;
- lo sviluppo prosegue da questa fase additiva;
- non rinumerare le migrazioni gia applicate e non riscrivere la storia Git;
- introdurre nuove migrazioni forward-only e compatibili con DB legacy e DB gia aggiornati alle Fasi 0-3.

Deliverable:

- migrazione additiva per `document_tags` con `uuid`, `version`, `metadata_sha256`, `deleted_at`;
- migrazione additiva per `scan_sources` con `uuid`, `version`, `metadata_sha256`, `deleted_at`;
- backfill non distruttivo per assegnazioni tag e scan source esistenti;
- helper o estensione degli helper esistenti per hash metadata di `document_tags` e `scan_sources`;
- aggiornamento dei write path che modificano assegnazioni tag e scan source per mantenere version/hash coerenti;
- estensione Manifest V3 con `document_tags[]` come fonte autorevole delle assegnazioni tag sincronizzabili;
- estensione Manifest V3 di `scan_sources[]` con UUID/version/hash/tombstone;
- import V3 idempotente dei nuovi payload, mantenendo compatibilita con V1/V2 e con V3 prodotti dalle commit precedenti;
- chiarimento o implementazione persistente di `visibility`, evitando valori hardcoded non rappresentati nello storage;
- aggiornamento `docs-node/README.md` per rimuovere la nota ormai superata che esclude `scan_sources` dalla baseline sync;
- aggiornamento `docs/server-capability-matrix.md` per dichiarare storage versionato, Manifest V3, remote-server read-only e replica read-only;
- smoke migration e Manifest V3 dedicati ai nuovi campi.

Criteri accettazione:

- DB vuoto, DB legacy e DB gia migrato alle Fasi 0-3 vengono aggiornati senza perdita dati;
- `document_tags` e `scan_sources` hanno UUID/version/hash/tombstone valorizzati dopo backfill;
- `set_document_tags`, `bulk_set_document_tags`, `scan_file`, `scan_folder`, `import_shelf` e `resync_all` mantengono metadata coerenti;
- export V3 contiene `document_tags[]` e `scan_sources[]` completi;
- import V3 accetta sia manifest nuovi sia manifest V3 precedenti privi dei nuovi campi;
- Fasi 0-3 continuano a passare con gli smoke esistenti;
- la documentazione non contiene piu indicazioni contraddittorie su `scan_sources`.

Rischio: medio. La modifica tocca schema e manifest, ma resta additiva e non introduce ancora changelog remoto, push o soft delete attivo.

#### Fase 4 — Changelog e pull incrementale

Obiettivo: evitare snapshot completi a ogni sync.

Deliverable:

- tabella `change_log`;
- generazione change log per operazioni write locali;
- endpoint `GET /sync/shelves/{uuid}/changes`;
- cursori per pull;
- applicazione delta inbound;
- attivazione semantica tombstone/soft delete per delete sincronizzabili, con filtri sulle letture legacy;
- test idempotenza replay.

Criteri accettazione:

- sync pull ripetuta non duplica cambi;
- delete remoto diventa tombstone locale;
- FTS viene aggiornato dopo delta;
- cursor persistito correttamente.

Rischio: alto, per consistenza dati.

#### Fase 5 — Publish e push read-write

Obiettivo: pubblicare scaffali locali e sincronizzare modifiche locali verso server.

Deliverable:

- `publish_shelf`;
- `sync_shelf direction=pull_push`;
- push batch con optimistic concurrency;
- ACL write server-side;
- conflitti persistiti;
- dry-run impatto push.

Criteri accettazione:

- shelf locale pubblicato su server;
- update locale arriva al remoto;
- update concorrente genera conflitto, non overwrite;
- utente vede conflitto in `list_conflicts`.

Rischio: alto.

#### Fase 6 — Risoluzione conflitti

Obiettivo: gestire modifiche concorrenti in modo operativo.

Deliverable:

- `sync_conflicts`;
- `list_conflicts`;
- `resolve_conflict`;
- strategie `use_local`, `use_remote`, `manual_merge`, `keep_both`;
- supporto 3-way merge Markdown semplice;
- report conflitti in `docs_navigation`.

Criteri accettazione:

- conflitto documento risolvibile;
- risoluzione genera nuova change log entry;
- conflitto risolto non si ripresenta al sync successivo;
- audit mantiene payload locale/remoto/base.

Rischio: alto.

#### Fase 7 — Seamless sync e hardening

Obiettivo: rendere la sincronizzazione usabile quotidianamente.

Deliverable:

- sync on startup opzionale;
- sync manuale esplicito;
- retry/backoff;
- stato visualizzabile;
- metriche minime;
- pruning changelog remoto configurabile;
- backup/export prima di operazioni rischiose;
- documentazione operativa.

Criteri accettazione:

- utente capisce stato sync senza leggere DB;
- conflitti non bloccano scaffali non coinvolti;
- retry non crea duplicati;
- server remoto robusto a disconnessioni.

Rischio: medio.

---

## 17. Piano test e validazione

### 17.1 Test esistenti da preservare

Lo smoke attuale su `docs-node` va mantenuto come regressione base:

- avvio server;
- scan file;
- lista documenti;
- ricerca;
- resources/list;
- resources/read.

### 17.2 Nuovi test migration

Aggiungere fixture:

```text
tests/fixtures/docs-node/legacy-v1/docs.db
tests/fixtures/docs-node/legacy-v2/docs.db
tests/fixtures/docs-node/empty/
```

Casi:

- DB vuoto;
- DB legacy senza `schema_migrations`;
- DB con documenti, tag e link;
- verifiche hash/versione documento quando mutano assegnazioni tag o il dizionario tag associato;
- DB con FTS non disponibile;
- migrazione interrotta rollback.

### 17.3 Test manifest

Casi:

- export V2 ancora valido;
- import V2 genera UUID;
- export V3 + import V3 roundtrip;
- import V3 idempotente;
- link inter-shelf risolti;
- warning non bloccanti per target mancanti.

### 17.4 Test sync read-only

Casi:

- configure remote;
- list remote shelves;
- subscribe shelf;
- sync snapshot;
- search replica;
- blocco write su read-only.

### 17.5 Test changelog

Casi:

- ogni write genera change log;
- replay idempotente;
- cursor aggiornato;
- tombstone applicato;
- FTS aggiornato.

### 17.6 Test conflitti

Casi:

- document update concorrente;
- tag add/add compatibile;
- tag add/remove conflittuale;
- document_link manual update concorrente;
- heuristic link non blocca sync;
- resolve use_local/use_remote/manual_merge.

### 17.7 Test sicurezza

Casi:

- richiesta senza token;
- token senza scope;
- token read-only prova write;
- Origin non permesso;
- secret non appare nei log;
- path traversal in snapshot/zip rifiutato.

### 17.8 Schema compatibility

Per ogni nuovo schema MCP:

- ogni `array` deve avere `items`;
- output duale `content` + `structuredContent` stabile;
- errori write chiari;
- fallback legacy documentato.

---

## 18. Backward compatibility

### 18.1 Compatibilita obbligatoria

Da preservare:

- `docs_management` con action esistenti;
- `docs_navigation` con action esistenti;
- URI `docs://document/{id}` e `docs://shelf/{id}-{slug}`;
- import manifest V1/V2;
- `DOCS_NODE_DB_PATH`;
- avvio via `stdio`;
- smoke esistente.

### 18.2 Nuove URI stabili

Aggiungere senza rimuovere le vecchie:

```text
docs://document/{uuid}
docs://shelf/{uuid}
```

`parseDocsUri()` deve supportare entrambi i formati.

### 18.3 Fallback per client severi

Se alcuni client MCP non supportano bene HTTP MCP o resources estese:

- mantenere stdio locale;
- esporre sync tramite tool `docs_remote` lato stdio;
- documentare HTTP come modalita server remota, non come requisito per uso locale.

---

## 19. Rischi e mitigazioni

| Rischio | Livello | Mitigazione |
|---|---:|---|
| Perdita dati durante migrazione | Alto | migrazioni transazionali, backup, fixture legacy |
| Sovrascrittura concorrente | Alto | optimistic concurrency e conflitti persistenti |
| Loop sync locale/remoto | Medio | `node_uuid`, `change_uuid`, idempotenza |
| Duplicazione entita | Medio | UUID globali, import idempotente |
| Token leak | Alto | auth_profile indiretto, redazione log |
| Client MCP incompatibili | Medio | stdio invariato, HTTP opzionale |
| Refactor eccessivo | Medio | milestone piccole, estrazione incrementale |
| FTS divergente | Basso | cache rigenerabile post-sync |
| Link euristici rumorosi | Medio | non farli prevalere sui manuali, min_confidence, rigenerazione |
| Server remoto single SQLite conteso | Medio | WAL, transazioni brevi, eventuale futuro Postgres |

---

## 20. Decisioni tecniche consigliate

### 20.1 Decisioni da adottare subito

1. **UUID obbligatori** per entita sincronizzabili.
2. **Schema migrations versionate** prima di nuove feature persistenti.
3. **Manifest V3** per snapshot sync.
4. **Tool separato `docs_remote`**.
5. **Stdio invariato** come compatibilita locale.
6. **HTTP MCP solo per remote-server**.
7. **Sync a livello shelf**, non singolo documento.
8. **Conflitti persistenti**, non overwrite automatico.
9. **Scaffali locali privati di default**.
10. **Read-only replica prima del read-write**.

### 20.2 Decisioni da rimandare

1. Passaggio da SQLite a Postgres lato server.
2. CRDT avanzati per Markdown.
3. Real-time bidirectional sync via SSE.
4. UI completa di risoluzione conflitti.
5. Multi-tenant complesso.
6. Cifratura end-to-end dei documenti.

---

## 21. Work breakdown suggerito per PR

### Baseline chiusa — Fasi 0-3

Le Fasi 0-3 sono considerate gia implementate e chiuse come baseline di sviluppo:

- Fase 0: schema migration baseline e metadata principali;
- Fase 1: Manifest V3 snapshot con compatibilita V1/V2;
- Fase 2: remote-server HTTP read-only;
- Fase 3: replica locale read-only con `docs_remote`.

Queste fasi non vanno riaperte con rewrite storico. Eventuali lacune rispetto a questa analisi aggiornata confluiscono nella Fase 3.5.

### PR 3.5 — Riallineamento schema/manifest/docs

File probabili:

```text
docs-node/index.js
docs-node/src/db/migrations.js
tests/smoke/docs-node-migrations.smoke.mjs
tests/smoke/docs-node-manifest-v3.smoke.mjs
docs-node/README.md
docs/server-capability-matrix.md
```

Attivita:

- aggiungere migrazione forward-only per `document_tags` e `scan_sources`;
- backfill UUID/version/hash/tombstone per le due entita;
- aggiornare write path per assegnazioni tag e scan source;
- estendere Manifest V3 con `document_tags[]` e metadata completi su `scan_sources[]`;
- mantenere import compatibile con manifest V3 precedenti privi dei nuovi array/campi;
- chiarire o persistere `visibility`;
- aggiornare README e capability matrix;
- ampliare smoke migration e manifest.

### PR 4 — Changelog pull

Attivita:

- tabella `change_log`;
- endpoint changes;
- cursor;
- apply delta;
- attivazione tombstone/soft delete per delete sincronizzabili.

### PR 5 — Publish/push/conflitti

Attivita:

- publish shelf;
- push changes;
- conflict detection;
- list/resolve conflicts.

---

## 22. Esempio prompt per Codex implementativo

```text
Repository: sophiadeveloper/mcp-servers
Ambito: docs-node
Skill: skills/mcp-technical-analyst + regole AGENTS.md

Le Fasi 0-3 sono chiuse. Implementa la Fase 3.5 di riallineamento additivo:
1. Non rinumerare le migrazioni gia applicate e non riscrivere la storia Git.
2. Aggiungi una migrazione forward-only per `document_tags` e `scan_sources` con `uuid`, `version`, `metadata_sha256`, `deleted_at`.
3. Esegui backfill non distruttivo per DB vuoti, legacy e gia migrati alle Fasi 0-3.
4. Aggiorna i write path per mantenere version/hash coerenti su assegnazioni tag e scan source (`set_document_tags`, `bulk_set_document_tags`, `scan_file`, `scan_folder`, `import_shelf`, `resync_all`).
5. Estendi Manifest V3 con `document_tags[]` autorevole e metadata completi in `scan_sources[]`, mantenendo compatibilita con V1/V2 e V3 precedenti.
6. Chiarisci o persisti `visibility` senza introdurre publish/push read-write.
7. Aggiorna README e `docs/server-capability-matrix.md`, rimuovendo indicazioni superate su `scan_sources`.
8. Aggiungi o estendi smoke migration/manifest per coprire i nuovi campi e la compatibilita backward.
9. Non introdurre ancora `change_log`, endpoint changes, push, conflitti o soft delete attivo: restano Fase 4+.
10. Rispetta AGENTS.md: cambi incrementali, compatibilita legacy, schema MCP strict-compatible.
```

---

## 23. Punti aperti

1. Il server remoto deve usare SQLite anche in produzione o si vuole prevedere Postgres in una fase successiva?
2. L'autenticazione deve essere solo token interna o OAuth/OIDC aziendale?
3. Gli scaffali remoti read-only devono essere modificabili localmente come fork privati?
4. I documenti fisici Markdown devono essere replicati su filesystem locale o solo nel DB SQLite?
5. Quale retention desiderata per `change_log` remoto?
6. La mappa mentale euristica deve essere sincronizzata o rigenerata localmente?
7. Serve una UI amministrativa per conflitti oppure basta tool MCP iniziale?

---

## 24. Raccomandazione finale

Procedere con l'evolutiva, ma in modo rigorosamente incrementale.

La baseline fino alla replica read-only e ora considerata chiusa. Il percorso residuo piu sicuro e:

1. completare Fase 3.5 con riallineamento additivo di schema, Manifest V3, write path, README e capability matrix;
2. introdurre changelog e pull incrementale solo dopo che `document_tags` e `scan_sources` hanno identita/versione/tombstone;
3. attivare soft delete/tombstone sincronizzabili in Fase 4, con filtri sulle letture legacy e test dedicati;
4. procedere poi con publish/push read-write e conflitti persistenti;
5. solo dopo consolidare sync seamless, retry, stato operativo e hardening.

Questa sequenza preserva l'attuale valore di `docs-node`, riduce il rischio di regressioni e rispetta le regole del repository: compatibilita legacy, milestone piccole, migrazioni non distruttive, smoke test e documentazione locale aggiornata.
