# docs-node MCP Server

Il server `docs-node` indicizza documenti Markdown in un database SQLite locale e supporta relazioni semantiche ("mappa mentale") tra documenti e scaffali.

Per default il database e' `docs-node/docs.db`. In test, sandbox o ambienti dove la cartella del server non e' scrivibile, impostare `DOCS_NODE_DB_PATH` a un path SQLite scrivibile.

## 1. Schema Database

Il database SQLite (`docs.db`) contiene le seguenti tabelle:

### `shelves`
* `id`: INTEGER PRIMARY KEY AUTOINCREMENT
* `name`: TEXT UNIQUE NOT NULL
* `description`: TEXT
* `commonRoot`: TEXT
* `created_at` / `updated_at`: TIMESTAMP

### `documents`
* `id`: INTEGER PRIMARY KEY AUTOINCREMENT
* `shelf_id`: INTEGER REFERENCES shelves(id) ON DELETE CASCADE
* `title`: TEXT NOT NULL
* `file_path`: TEXT UNIQUE NOT NULL
* `content`: TEXT
* `headings`: TEXT (JSON array di heading estratti)
* `tags`: TEXT (JSON array di tag)
* `created_at` / `updated_at`: TIMESTAMP

### `shelf_links` (Nuovo)
Rappresenta relazioni parent/child tra scaffali (ad es. per estendere scaffali standard con varianti cliente).
* `parent_shelf_id`: INTEGER REFERENCES shelves(id) ON DELETE CASCADE
* `child_shelf_id`: INTEGER REFERENCES shelves(id) ON DELETE CASCADE
* `relation`: TEXT NOT NULL DEFAULT 'parent'
* `created_at` / `updated_at`: TIMESTAMP
* *PRIMARY KEY(parent_shelf_id, child_shelf_id, relation)* (con check di ciclo transitivo)

### `document_links` (Nuovo)
Memorizza relazioni direzionali molti-a-molti tra documenti.
* `id`: INTEGER PRIMARY KEY AUTOINCREMENT
* `source_document_id`: INTEGER REFERENCES documents(id) ON DELETE CASCADE
* `target_document_id`: INTEGER REFERENCES documents(id) ON DELETE CASCADE
* `relation`: TEXT NOT NULL (es. `extends_standard`, `references_standard`, `references_custom`, `mentions`)
* `score`: REAL (punteggio calcolato)
* `confidence`: REAL (livello di confidenza da 0 a 1)
* `origin`: TEXT NOT NULL (`manual` o `heuristic`)
* `heuristic_version`: TEXT
* `label`: TEXT
* `rationale`: TEXT
* `metadata_json`: TEXT
* `created_at` / `updated_at`: TIMESTAMP
* *UNIQUE(source_document_id, target_document_id, relation, origin)*

---

## 2. Contratti MCP Principali

### `docs_management`

#### `manage_shelf_links`
Gestisce le relazioni gerarchiche tra scaffali. Evita cicli in modo transitivo.
```json
{
  "action": "manage_shelf_links",
  "operation": "add_parent" | "remove_parent" | "set_parents" | "list",
  "shelf": "Nome Scaffale",
  "parent_shelf": "Nome Parent",        // Per add/remove
  "parent_shelves": ["Parent1", "Parent2"] // Per set_parents
}
```

#### `manage_document_links`
Gestisce i collegamenti direzionali manuali tra documenti.
```json
{
  "action": "manage_document_links",
  "operation": "add" | "remove" | "list" | "replace_for_document",
  "source_document_id": 101,
  "target_document_id": 22,
  "relation": "references_standard",
  "confidence": 1.0,
  "label": "Descrizione opzionale",
  "rationale": "Razionale opzionale"
}
```

#### `correlate`
Esegue l'algoritmo di correlazione euristica per trovare documenti correlati.
```json
{
  "action": "correlate",
  "mode": "document" | "shelf",
  "document_id": 101,               // Richiesto se mode="document"
  "shelf": "Nome Scaffale",         // Richiesto se mode="shelf"
  "scope": "shelf_with_parents" | "shelf" | "cross_shelf",
  "min_confidence": 0.6,
  "min_signal_count": 2,
  "max_links_per_document": 8,
  "apply": false                    // Impostare a true per scrivere fisicamente nel DB
}
```

L'euristica e' pensata soprattutto per bootstrap/triage rapido della mappa mentale. Dopo
l'inizializzazione, i collegamenti piu' affidabili vanno inseriti sul momento con
`manage_document_links`, usando il contesto funzionale effettivo dell'analisi in corso.
Per ripulire link euristici deboli senza toccare quelli manuali:

```json
{
  "action": "manage_document_links",
  "operation": "prune_heuristic_links",
  "shelf": "Cliente X",
  "max_confidence": 0.55,
  "apply": false
}
```

Usare prima `apply:false` per vedere i candidati; `apply:true` elimina solo link con
`origin="heuristic"` nello scope selezionato.

---

## 3. Algoritmo di Correlazione Euristica

Il motore di correlazione confronta i documenti calcolando un punteggio pesato:

1. **Title Similarity** (peso: `0.25`): Jaccard similarity sui token dei titoli.
2. **Heading Similarity** (peso: `0.20`): Jaccard similarity sugli heading Markdown.
3. **Tag Overlap** (peso: `0.20`): Jaccard similarity sui tag assegnati ai documenti.
4. **Keyword Overlap** (peso: `0.15`): Overlap delle top 30 parole chiave (escluse stopword comuni).
5. **Path Proximity** (peso: `0.10`): Vicinanza nel filesystem (`1.0` se nella stessa cartella, `0.5` se sotto lo stesso parent comune, `0` altrimenti).
6. **Explicit Mention** (peso: `0.10`): `1.0` se il testo del documento sorgente cita esplicitamente il titolo o il nome file del target.

`min_signal_count` permette di scartare candidati sostenuti da un solo segnale debole
(tipicamente solo tag generici o sola vicinanza di path). Il report di `correlate`
include `signals` nei `sample_links` e salva gli stessi segnali in `metadata_json` per
audit successivo.

### Regole di Routing Direzionale
* I link da documenti in scaffali "child" a documenti in scaffali "parent" sono permessi ed incoraggiati (es. varianti cliente che puntano allo standard).
* I link da scaffali "parent" a scaffali "child" sono esclusi automaticamente per evitare di inquinare la documentazione del framework generico con casi specifici del cliente.

---

## 4. Manifest V2 per Import/Export

L'export degli scaffali genera un manifest con `format_version: 2`. I link vengono serializzati usando `relative_path` (calcolato rispetto al root comune dello scaffale) invece che ID di database, rendendo i pacchetti esportati indipendenti dall'istanza locale e portabili tra diversi workspace. L'importatore risolve dinamicamente i percorsi e genera warning non bloccanti se i link non possono essere risolti.

---

## 5. Esecuzione Test

Per verificare la correttezza del server e delle nuove funzionalità della mappa mentale:
```bash
npm run smoke
```
Oppure:
```bash
node tests/smoke/docs-node.smoke.mjs
```
