**Motivations:** - Align master with current codebase (token from projects/<id>/.secrets/<env>/ia_token) - Id resolution by mail To or by API token; no slug **Root causes:** - Token moved from conf.json to .secrets/<env>/ia_token; env from directory name **Correctifs:** - Server and scripts resolve project+env by scanning all projects and envs **Evolutions:** - tickets-fetch-inbox routes by To address; notary-ai agents and API doc updated **Pages affectées:** - ai_working_help/server.js, docs, project_config.py, lib/project_config.sh - projects/README.md, lecoffreio/docs/API.md, gitea-issues/tickets-fetch-inbox.py
842 lines
26 KiB
Markdown
842 lines
26 KiB
Markdown
# Documentation Complète de l'Ancrage Blockchain - LeCoffre.io
|
|
|
|
**Dernière mise à jour** : 2025-11-24
|
|
**Version** : 3.1.2
|
|
|
|
Ce document consolide toute la documentation relative à l'ancrage blockchain des documents et dossiers dans LeCoffre.io.
|
|
|
|
---
|
|
|
|
## 📋 Table des Matières
|
|
|
|
1. [Vue d'Ensemble](#1-vue-densemble)
|
|
2. [Architecture V3](#2-architecture-v3)
|
|
3. [Processus d'Ancrage](#3-processus-dancrage)
|
|
4. [Certificats et ZIP](#4-certificats-et-zip)
|
|
5. [Vérification et Statuts](#5-vérification-et-statuts)
|
|
6. [Scripts et Maintenance](#6-scripts-et-maintenance)
|
|
7. [Troubleshooting](#7-troubleshooting)
|
|
8. [Références](#8-références)
|
|
|
|
---
|
|
|
|
## 1. Vue d'Ensemble
|
|
|
|
### Évolution des Versions
|
|
|
|
| Version | Blockchain | Périmètre | Déclenchement | Filigrane | Fallback |
|
|
|---------|-----------|-----------|---------------|-----------|----------|
|
|
| **V1** | Tezos | Dossiers uniquement | Manuel | ❌ Non | ⚠️ Lecture seule |
|
|
| **V2** | Bitcoin Signet | Docs + Dossiers | Auto | ❌ Non | - |
|
|
| **V3** | Bitcoin Signet | Docs + Dossiers | Auto | ✅ Oui | ✅ Tezos masqué |
|
|
|
|
### Nouveautés V3
|
|
|
|
1. **Filigrane automatique** : "lecoffre.io" sur tous documents
|
|
2. **Double version** : Original + filigrané (conservés en BDD)
|
|
3. **ZIP enrichi** : Originaux + filigranés + certificats + preuves JSON
|
|
4. **Preuves structurées** : JSON standardisé pour vérification externe
|
|
5. **Ancrage dossier** : Hash du ZIP complet (pas seulement Merkle tree)
|
|
6. **Fallback Tezos** : Accès masqué aux anciens ancrages (lecture seule)
|
|
|
|
### Principes Fondamentaux
|
|
|
|
- **Ancrage immédiat** : L'ancrage est déclenché automatiquement lors de la validation d'un document
|
|
- **Hash filigrané** : Seule la version filigranée est ancrée sur blockchain
|
|
- **Double hash** : Hash original et hash filigrané sont stockés pour vérification
|
|
- **Preuve on-chain** : Le `tx_id` (transaction ID Bitcoin) est la seule preuve fiable d'ancrage
|
|
|
|
---
|
|
|
|
## 2. Architecture V3
|
|
|
|
### Services Backend
|
|
|
|
#### WatermarkService
|
|
|
|
**Fichier** : `lecoffre-back-main/src/services/common/WatermarkService/WatermarkService.ts`
|
|
|
|
**Responsabilités** :
|
|
|
|
- Conversion documents → PDF (si nécessaire)
|
|
- Ajout filigrane "lecoffre.io" (diagonal, 15% opacité)
|
|
- Upload version filigranée vers S3/IPFS
|
|
- Gestion formats : PDF, images, Word, PowerPoint
|
|
|
|
**Méthodes principales** :
|
|
|
|
```typescript
|
|
async addWatermarkAndUpload(fileUid: string): Promise<{
|
|
watermarkedS3Key: string;
|
|
watermarkedSize: number;
|
|
watermarkedMimetype: string;
|
|
}>
|
|
```
|
|
|
|
#### DocumentAnchorsService
|
|
|
|
**Fichier** : `lecoffre-back-main/src/services/notary/DocumentAnchorsService/DocumentAnchorsService.ts`
|
|
|
|
**Workflow d'ancrage** :
|
|
|
|
1. Vérification ancrage Tezos existant (fallback)
|
|
2. Génération version filigranée si absente
|
|
3. Calcul hash version filigranée
|
|
4. Vérification ancrage Signet existant
|
|
5. Création ancrage `QUEUED`
|
|
6. Ancrage blockchain Bitcoin Signet
|
|
7. Génération `proof_data` (incluant fallback Tezos)
|
|
8. Mise à jour ancrage avec `tx_id`
|
|
|
|
**Méthodes principales** :
|
|
|
|
```typescript
|
|
async anchorDocument(documentUid: string, anchoredByUid?: string): Promise<DocumentAnchors>
|
|
async getByDocumentUid(documentUid: string): Promise<DocumentAnchors | null>
|
|
async getByFileHash(fileHash: string): Promise<DocumentAnchors | null>
|
|
```
|
|
|
|
#### OfficeFolderAnchorsService
|
|
|
|
**Fichier** : `lecoffre-back-main/src/services/notary/OfficeFolderAnchorsService/OfficeFolderAnchorsService.ts`
|
|
|
|
**Workflow d'ancrage dossier** :
|
|
|
|
1. Récupération tous documents validés
|
|
2. Génération filigranes manquants
|
|
3. Génération ZIP complet dossier
|
|
4. Upload ZIP vers S3
|
|
5. Ancrage hash ZIP complet
|
|
6. Génération preuve dossier
|
|
|
|
**Structure ZIP** :
|
|
|
|
```text
|
|
dossier_12345678/
|
|
├── _LISEZ-MOI.txt
|
|
├── 01_originaux/
|
|
├── 02_filigranes/
|
|
├── 03_certificats/
|
|
└── 04_preuves/
|
|
```
|
|
|
|
#### ProofDataService
|
|
|
|
**Fichier** : `lecoffre-back-main/src/services/notary/ProofDataService/ProofDataService.ts`
|
|
|
|
**Responsabilités** :
|
|
|
|
- Génération JSON de preuve d'ancrage
|
|
- Format standard pour vérification externe
|
|
- Inclusion toutes données blockchain
|
|
|
|
**Structure JSON** :
|
|
|
|
```json
|
|
{
|
|
"version": "3.0.0",
|
|
"timestamp": "2025-10-29T16:30:00.000Z",
|
|
"document": {
|
|
"uid": "abc123...",
|
|
"name": "Acte de vente",
|
|
"original_hash": "e3b0c442...",
|
|
"watermarked_hash": "5feceb66..."
|
|
},
|
|
"anchor": {
|
|
"blockchain": "BITCOIN_SIGNET",
|
|
"status": "VERIFIED_ON_CHAIN",
|
|
"txid": "a1b2c3d4...",
|
|
"tx_link": "https://mempool.4nkweb.com/signet/tx/a1b2c3d4...",
|
|
"block_height": 123456,
|
|
"confirmations": 6
|
|
},
|
|
"tezos_fallback": {
|
|
"legacy": true,
|
|
"blockchain": "TEZOS",
|
|
"txid": "old_tezos_tx..."
|
|
}
|
|
}
|
|
```
|
|
|
|
#### BitcoinSignetService
|
|
|
|
**Fichier** : `lecoffre-back-main/src/services/common/BitcoinSignetService/BitcoinSignetService.ts`
|
|
|
|
**Responsabilités** :
|
|
|
|
- Ancrage hash sur Bitcoin Signet
|
|
- Vérification statut transaction
|
|
- Récupération métadonnées blockchain
|
|
|
|
**Méthodes principales** :
|
|
|
|
```typescript
|
|
async anchorHash(hash: string): Promise<{
|
|
txid: string;
|
|
tx_hash: string;
|
|
tx_link: string;
|
|
}>
|
|
async verifyAnchor(txId: string): Promise<{
|
|
confirmed: boolean;
|
|
confirmations: number;
|
|
block_height: number;
|
|
}>
|
|
```
|
|
|
|
### Base de Données
|
|
|
|
#### Schéma Prisma
|
|
|
|
**Table `files`** :
|
|
|
|
```prisma
|
|
model Files {
|
|
uid String @id @unique @default(uuid())
|
|
file_name String
|
|
s3_key String?
|
|
|
|
// V3 : Version filigranée
|
|
watermarked_s3_key String?
|
|
watermarked_at DateTime?
|
|
original_hash String? // Hash fichier original
|
|
|
|
document_uid String?
|
|
document Documents? @relation(...)
|
|
}
|
|
```
|
|
|
|
**Table `document_anchors`** :
|
|
|
|
```prisma
|
|
model DocumentAnchors {
|
|
uid String @id @unique @default(uuid())
|
|
document_uid String @unique
|
|
|
|
// Hash de la version FILIGRANNÉE (V3)
|
|
file_hash String
|
|
|
|
blockchain EBlockchainName @default(BITCOIN_SIGNET)
|
|
status EAnchoringStatus @default(QUEUED)
|
|
|
|
// Données blockchain
|
|
tx_id String? // ⚠️ CRITIQUE : Seul indicateur fiable
|
|
tx_link String?
|
|
tx_hash String?
|
|
block_height Int?
|
|
block_time DateTime?
|
|
confirmations Int?
|
|
|
|
// V3 : Données de preuve (JSON)
|
|
proof_data Json?
|
|
|
|
anchored_at DateTime?
|
|
anchored_by_uid String?
|
|
}
|
|
```
|
|
|
|
**Table `office_folder_anchors`** :
|
|
|
|
```prisma
|
|
model OfficeFolderAnchors {
|
|
uid String @id @unique @default(uuid())
|
|
|
|
// Hashs sources (Merkle tree)
|
|
root_hash String
|
|
|
|
// V3 : ZIP complet
|
|
zip_hash String?
|
|
zip_s3_key String?
|
|
zip_size Float?
|
|
|
|
blockchain EBlockchainName @default(BITCOIN_SIGNET)
|
|
status EAnchoringStatus @default(QUEUED)
|
|
|
|
// Données blockchain
|
|
tx_id String? // ⚠️ CRITIQUE : Seul indicateur fiable
|
|
tx_link String?
|
|
tx_hash String?
|
|
block_height Int?
|
|
confirmations Int?
|
|
|
|
// V3 : Données de preuve (JSON)
|
|
proof_data Json?
|
|
}
|
|
```
|
|
|
|
**Enums** :
|
|
|
|
```prisma
|
|
enum EBlockchainName {
|
|
TEZOS // ⚠️ Conservé pour fallback (lecture seule)
|
|
BITCOIN_SIGNET
|
|
}
|
|
|
|
enum EAnchoringStatus {
|
|
QUEUED // ⚠️ OBSOLÈTE : Non utilisé de manière fiable
|
|
ATTEMPTING // ⚠️ OBSOLÈTE : Non utilisé de manière fiable
|
|
VERIFIED_ON_CHAIN // ⚠️ OBSOLÈTE : Le système se base uniquement sur tx_id
|
|
FAILED
|
|
ABANDONED
|
|
}
|
|
```
|
|
|
|
**⚠️ IMPORTANT** : Le champ `status` n'est plus utilisé de manière fiable. Le système vérifie uniquement la présence de `tx_id` :
|
|
|
|
- `tx_id` présent = Ancrage réussi
|
|
- `tx_id` absent = Ancrage non effectué
|
|
|
|
---
|
|
|
|
## 3. Processus d'Ancrage
|
|
|
|
### Séquence de Traitement (Upload)
|
|
|
|
Pour **tous les documents** (Client, Tiers, Notaire invité, Notaire), la séquence est :
|
|
|
|
1. **Calcul hash original** (fichier original)
|
|
2. **Filigrane** (sur fichier original non chiffré)
|
|
3. **Calcul hash filigrané et ancrage blockchain** (hash filigrané, génération txid)
|
|
4. **Chiffrement** du document filigrané
|
|
5. **Upload IPFS** du document chiffré
|
|
6. **Stockage métadonnées** fichier (hash original + hash filigrané)
|
|
7. **Stockage certificat BDD** (document_anchor avec hash filigrané + hash original + txid)
|
|
|
|
### Ancrage Automatique lors de la Validation
|
|
|
|
**Déclenchement** : Lors de la validation d'un document via `PUT /api/v1/notary/documents/:uid`
|
|
|
|
**Fichier** : `lecoffre-back-main/src/app/api/notary/DocumentsController.ts`
|
|
|
|
**Workflow** :
|
|
|
|
```typescript
|
|
if (documentEntityUpdated.document_status === EDocumentStatus.VALIDATED && firstFileUid) {
|
|
// Ancrage automatique (asynchrone, non bloquant)
|
|
if (userUid) {
|
|
void this.documentAnchorsService
|
|
.anchorDocument(documentEntityUpdated.uid, userUid)
|
|
.then((anchor) => {
|
|
SafeLogger.info(`✅ Document ${documentEntityUpdated.uid} automatically anchored`);
|
|
})
|
|
.catch((error) => {
|
|
SafeLogger.error(`❌ Auto-anchoring failed: ${error}`);
|
|
});
|
|
}
|
|
}
|
|
```
|
|
|
|
**Points importants** :
|
|
|
|
- ✅ L'ancrage est **asynchrone** (non bloquant)
|
|
- ✅ L'ancrage est lancé en **arrière-plan**
|
|
- ✅ Si l'ancrage échoue, le document reste validé
|
|
|
|
### Ancrage Document
|
|
|
|
**Workflow détaillé** :
|
|
|
|
1. **Récupération document + fichier**
|
|
2. **Vérification ancrage Tezos existant** (fallback)
|
|
3. **Génération version filigranée** si absente
|
|
4. **Téléchargement version filigranée** et calcul hash
|
|
5. **Vérification ancrage Signet existant**
|
|
6. **Création ancrage `QUEUED`**
|
|
7. **Ancrage blockchain** via `BitcoinSignetService.anchorHash()`
|
|
8. **Génération `proof_data`** (incluant fallback Tezos)
|
|
9. **Mise à jour ancrage** avec `tx_id`, `tx_link`, `proof_data`
|
|
|
|
### Ancrage Dossier
|
|
|
|
**Workflow détaillé** :
|
|
|
|
1. **Récupération tous documents validés** du dossier
|
|
2. **Génération filigranes manquants** pour tous documents
|
|
3. **Génération ZIP complet** du dossier :
|
|
- Originaux (01_originaux/)
|
|
- Filigranés (02_filigranes/)
|
|
- Certificats (03_certificats/)
|
|
- Preuves JSON (04_preuves/)
|
|
4. **Upload ZIP vers S3**
|
|
5. **Ancrage hash ZIP complet** sur blockchain
|
|
6. **Génération preuve dossier**
|
|
7. **Création/Mise à jour ancrage dossier**
|
|
|
|
**Condition** : Le dossier doit être à **100% de complétion** (tous documents validés)
|
|
|
|
---
|
|
|
|
## 4. Certificats et ZIP
|
|
|
|
### Génération Automatique de Certificats
|
|
|
|
#### Téléchargement Individuel (Document Validé et Ancré)
|
|
|
|
**Endpoints** :
|
|
|
|
- Notaire : `GET /api/v1/notary/files/download/:uid`
|
|
- Client : `GET /api/v1/customer/files/download/:uid`
|
|
|
|
**Comportement automatique** : Pour les documents validés (`VALIDATED`) et ancrés avec statut `VERIFIED_ON_CHAIN`, le téléchargement génère **automatiquement** un ZIP contenant :
|
|
|
|
1. **PDF filigrané** : Document avec filigrane appliqué (suffixe `_aplc.pdf`)
|
|
2. **Certificat d'ancrage** : Certificat PDF Bitcoin Signet (préfixe `certificat_`)
|
|
|
|
**Exemple de ZIP** :
|
|
|
|
```text
|
|
document_001_CNI_DUPONT_Jean_avec_certificat.zip
|
|
├── 001_CNI_DUPONT_Jean_aplc.pdf (PDF filigrané)
|
|
└── certificat_001_CNI_DUPONT_Jean.pdf (Certificat d'ancrage)
|
|
```
|
|
|
|
#### Téléchargement Multiple (ZIP de Fichiers)
|
|
|
|
**Service** : `ZipService.createZipFromFiles()`
|
|
|
|
**Workflow de recherche d'ancrage** :
|
|
|
|
1. **PRIORITÉ** : Recherche par `document_uid` (plus fiable)
|
|
2. **FALLBACK** : Si pas trouvé, recherche par hash du fichier
|
|
3. **Vérification statut** : Le certificat n'est généré que si `status === VERIFIED_ON_CHAIN`
|
|
|
|
#### Téléchargement Dossier Complet
|
|
|
|
**Service** : `OfficeFolderAnchorsService.generateFolderZip()`
|
|
|
|
**Structure ZIP** :
|
|
|
|
```text
|
|
dossier_12345678_Acte_de_vente/
|
|
├── _LISEZ-MOI.txt (Instructions vérification)
|
|
├── 01_originaux/
|
|
│ ├── acte_vente.pdf (Version originale)
|
|
│ └── compromis_vente.pdf
|
|
├── 02_filigranes/
|
|
│ ├── acte_vente.pdf (⚠️ VERSION ANCRÉE avec filigrane)
|
|
│ └── compromis_vente.pdf
|
|
├── 03_certificats/
|
|
│ ├── certificat_acte_vente.pdf (PDF certif blockchain)
|
|
│ └── certificat_compromis_vente.pdf
|
|
└── 04_preuves/
|
|
├── preuve_acte_vente.json (JSON avec hashs + TX)
|
|
└── preuve_compromis_vente.json
|
|
```
|
|
|
|
### Contenu des Certificats PDF
|
|
|
|
**Informations affichées** :
|
|
|
|
1. **Hashs complets** :
|
|
- Empreinte SHA-256 (original) : Hash complet du document initial (64 caractères hex)
|
|
- Empreinte SHA-256 (filigrané) : Hash complet du document avec filigrane (64 caractères hex)
|
|
- Source : `proof_data.document.original_hash` et `proof_data.document.watermarked_hash`
|
|
|
|
2. **Lien de transaction** :
|
|
- Format : `https://mempool.4nkweb.com/fr/tx/<txid>`
|
|
- Construit automatiquement à partir de `anchor.tx_id` si disponible
|
|
- Fallback sur `anchor.tx_link` si `tx_id` absent
|
|
|
|
3. **Autres informations** :
|
|
- Identifiant unique du document
|
|
- Informations du dossier (numéro, nom)
|
|
- Informations de l'office notarial
|
|
- Type de document
|
|
- Déposant
|
|
- Validateur (UID)
|
|
- Nom de fichier normé
|
|
- Blockchain utilisée (Bitcoin Signet Notaires)
|
|
- Statut d'ancrage
|
|
- ID de transaction
|
|
- Hauteur de bloc (si disponible)
|
|
- Date d'ancrage
|
|
|
|
### Filigrane Visuel
|
|
|
|
**Spécifications** :
|
|
|
|
- **Texte** : "lecoffre.io"
|
|
- **Position** : Diagonal (45°), centré sur chaque page
|
|
- **Opacité** : 15% (visible mais non gênant)
|
|
- **Couleur** : Gris clair (#CCCCCC)
|
|
- **Police** : Arial, 48pt
|
|
- **Pages** : Toutes les pages du PDF
|
|
|
|
---
|
|
|
|
## 5. Vérification et Statuts
|
|
|
|
### Logique de Vérification
|
|
|
|
**⚠️ IMPORTANT** : Le système d'ancrage V3 ne fonctionne plus avec des statuts intermédiaires. L'ancrage est maintenant **immédiat** :
|
|
|
|
- ✅ **Ancré** : L'ancrage a un `tx_id` (transaction ID Bitcoin)
|
|
- ❌ **Non ancré** : L'ancrage n'a pas de `tx_id`
|
|
|
|
**Il n'y a plus d'étape intermédiaire** comme `ATTEMPTING`, `QUEUED`, ou `VERIFYING_ON_CHAIN`.
|
|
|
|
### Backend
|
|
|
|
Le backend vérifie uniquement la présence de `tx_id` :
|
|
|
|
```typescript
|
|
if (anchorStatus.tx_id) {
|
|
setAnchorStatus(AnchorStatus.VERIFIED_ON_CHAIN);
|
|
} else {
|
|
setAnchorStatus(AnchorStatus.NOT_ANCHORED);
|
|
}
|
|
```
|
|
|
|
### Frontend
|
|
|
|
Le frontend utilise l'enum `AnchorStatus` mais ne vérifie que `tx_id` :
|
|
|
|
```typescript
|
|
export enum AnchorStatus {
|
|
"VERIFIED_ON_CHAIN" = "VERIFIED_ON_CHAIN",
|
|
"NOT_ANCHORED" = "NOT_ANCHORED",
|
|
}
|
|
|
|
// Vérification
|
|
if (anchorStatus.tx_id) {
|
|
setAnchorStatus(AnchorStatus.VERIFIED_ON_CHAIN);
|
|
} else {
|
|
setAnchorStatus(AnchorStatus.NOT_ANCHORED);
|
|
}
|
|
```
|
|
|
|
### Masquage du Statut "Ancrage en cours"
|
|
|
|
**Objectif** : Améliorer l'expérience utilisateur en ne montrant pas le statut transitoire "Ancrage en cours" pour les documents validés.
|
|
|
|
**Comportement** : Pour les documents avec `document_status === VALIDATED`, le statut "Ancrage en cours" (`ATTEMPTING`) n'est **pas affiché** dans l'interface utilisateur.
|
|
|
|
**Composant `AnchorBadge`** :
|
|
|
|
```typescript
|
|
if (documentStatus === "VALIDATED" && status === "ATTEMPTING") {
|
|
return null; // Badge not displayed
|
|
}
|
|
```
|
|
|
|
### Vérification Publique
|
|
|
|
**Endpoints** :
|
|
|
|
- `GET /api/v1/public/verify/:hash` : Vérification par hash (SANS authentification)
|
|
- `POST /api/v1/public/verify-file` : Vérification par upload fichier (SANS authentification)
|
|
|
|
**Page frontend** : `/verify-document`
|
|
|
|
**Fonctionnalités** :
|
|
|
|
- Upload fichier (drag & drop ou sélection)
|
|
- Calcul hash automatique (SHA256)
|
|
- Appel API public (aucune authentification requise)
|
|
- Affichage résultat (success/error)
|
|
- Lien explorateur blockchain
|
|
|
|
### Procédure de Vérification
|
|
|
|
**Pour utilisateur final** :
|
|
|
|
1. Télécharger ZIP complet du dossier
|
|
2. Extraire le ZIP
|
|
3. Ouvrir fichier dans `04_preuves/preuve_XXX.json`
|
|
4. Noter le `watermarked_hash`
|
|
5. Calculer hash du fichier dans `02_filigranes/` :
|
|
|
|
```bash
|
|
shasum -a 256 02_filigranes/acte_vente.pdf
|
|
```
|
|
|
|
6. Comparer les deux hashs (doivent être identiques)
|
|
7. Vérifier TX : Ouvrir `tx_link` du JSON dans navigateur
|
|
8. ✅ **Validé** si hash OK + TX confirmée sur blockchain
|
|
|
|
**Pour audit technique** :
|
|
|
|
1. Parser JSON de preuve
|
|
2. Extraire `watermarked_hash`, `txid`, `block_height`
|
|
3. Requête API blockchain (Mempool Space) :
|
|
|
|
```bash
|
|
curl https://mempool.4nkweb.com/signet/api/tx/{txid}
|
|
```
|
|
|
|
4. Vérifier :
|
|
- TX existe
|
|
- Hash dans OP_RETURN correspond
|
|
- Block confirmé
|
|
5. Recalculer hash fichier filigrané
|
|
6. Comparer avec `watermarked_hash`
|
|
7. ✅ **Preuve authentique** si tout correspond
|
|
|
|
---
|
|
|
|
## 6. Scripts et Maintenance
|
|
|
|
### Scripts Disponibles
|
|
|
|
#### Audit des Ancrages Manquants
|
|
|
|
**Script** : `audit-missing-anchors.js`
|
|
|
|
**Usage** :
|
|
|
|
```bash
|
|
ENV=prod npm run anchorage:audit
|
|
```
|
|
|
|
**Description** :
|
|
|
|
- Analyse tous les documents validés sans ancrage
|
|
- Analyse tous les dossiers archivés sans ancrage
|
|
- Génère un CSV avec la liste des documents/dossiers à réancrer
|
|
- Ne modifie aucune donnée (lecture seule)
|
|
|
|
**Résultat** :
|
|
|
|
- Affichage console avec statistiques
|
|
- CSV généré : `logs/audit-missing-anchors_YYYYMMDD_HHMMSS.csv`
|
|
|
|
#### Ancrage V3 de Dossiers Existants
|
|
|
|
**Script** : `anchor-existing-folders-v3.js`
|
|
|
|
**Usage** :
|
|
|
|
```bash
|
|
# Ancrage tous dossiers LIVE + ARCHIVED (par défaut)
|
|
ENV=prod npm run anchorage
|
|
|
|
# Dry-run (simulation)
|
|
ENV=prod npm run anchorage -- --all --batch=1 --dry-run
|
|
|
|
# Ancrage réel avec limite batch
|
|
ENV=prod npm run anchorage -- --all --batch=5
|
|
|
|
# Ancrage de dossiers spécifiques
|
|
ENV=prod npm run anchorage -- --folder-uids=uid1,uid2,uid3
|
|
```
|
|
|
|
**Options** :
|
|
|
|
- `--all-archived` : Tous les dossiers ARCHIVED sans ancrage
|
|
- `--all-validated` : Tous les dossiers VALIDATED sans ancrage
|
|
- `--all` : Tous les dossiers VALIDATED + ARCHIVED
|
|
- `--folder-uids=uid1,uid2,...` : Liste UIDs dossiers spécifiques
|
|
- `--batch=N` : Nombre max de dossiers par batch (défaut: 10)
|
|
- `--dry-run` : Simulation sans ancrage réel
|
|
- `--skip-documents` : Ancrer seulement dossiers (pas documents individuels)
|
|
|
|
#### Vérifications Systématisées des Colonnes d'Ancrage
|
|
|
|
Depuis 2025-01-XX, les scripts de déploiement vérifient systématiquement la présence des colonnes indispensables pour l'ancrage avant d'exécuter le réancrage.
|
|
|
|
**Colonnes vérifiées** :
|
|
|
|
- `document_anchors.proof_data` (JSONB) - Données de preuve structurées
|
|
- `document_anchors.confirmations` (INTEGER) - Nombre de confirmations blockchain
|
|
- `document_anchors.anchor_job_id` (VARCHAR) - ID du job d'ancrage
|
|
- `document_notary_anchors.proof_data` (JSONB) - Données de preuve structurées
|
|
- `document_notary_anchors.confirmations` (INTEGER) - Nombre de confirmations blockchain
|
|
|
|
**Garanties** :
|
|
|
|
- ✅ Vérification de l'existence des tables avant toute modification
|
|
- ✅ Ajout automatique des colonnes manquantes (8 points de vérification)
|
|
- ✅ Blocage du réancrage si colonnes manquantes détectées
|
|
- ✅ Messages d'erreur explicites indiquant les colonnes manquantes
|
|
|
|
**Ordre d'exécution garanti** :
|
|
|
|
```text
|
|
resetDatabase → migrateResolveDatabase → reanchorAll
|
|
↓ ↓ ↓
|
|
Base vide Colonnes ajoutées Vérification finale
|
|
↓ ↓
|
|
Si manquantes → Blocage si manquantes
|
|
```
|
|
|
|
📖 Voir [README.md](./README.md#consolidation-operationnelle-ex-operationsmd) et [DEPLOYMENT.md](./DEPLOYMENT.md) pour les corrections sur les colonnes d'ancrage.
|
|
|
|
#### Réancrage de Documents/Dossiers
|
|
|
|
**Script** : `reanchor-documents.js`
|
|
|
|
**Usage** :
|
|
|
|
```bash
|
|
# Dry-run (simulation)
|
|
ENV=prod npm run anchorage:reanchor -- --dry-run
|
|
|
|
# Réancrage réel
|
|
ENV=prod npm run anchorage:reanchor -- --document-uids=uid1,uid2
|
|
```
|
|
|
|
**Options** :
|
|
|
|
- `--document-uids=uid1,uid2,...` : Liste UIDs documents spécifiques
|
|
- `--folder-uids=uid1,uid2,...` : Liste UIDs dossiers spécifiques
|
|
- `--all-missing` : Réancrer TOUS les documents/dossiers sans ancrage (⚠️)
|
|
- `--batch=N` : Nombre max de documents/dossiers par batch (défaut: 50)
|
|
- `--dry-run` : Simulation sans ancrage réel
|
|
|
|
#### Nettoyage Ancres Dossiers Incomplets
|
|
|
|
**Script** : `clean-incomplete-folder-anchors.ts`
|
|
|
|
**Contexte** :
|
|
|
|
- Certains dossiers peuvent avoir été ancrés alors qu'ils n'étaient pas à 100%
|
|
- Seuls les dossiers complets (100% documents validés) doivent être ancrés
|
|
|
|
**Usage** :
|
|
|
|
```bash
|
|
# Depuis le conteneur backend
|
|
cd lecoffre-back-main
|
|
npx ts-node src/scripts/clean-incomplete-folder-anchors.ts --dry-run
|
|
npx ts-node src/scripts/clean-incomplete-folder-anchors.ts
|
|
```
|
|
|
|
**Actions** :
|
|
|
|
- Identifie les dossiers ancrés avec complétion < 100%
|
|
- Supprime les ancres correspondantes dans `office_folder_anchors`
|
|
- Réinitialise les liens `folder_anchor_uid = NULL` dans `office_folders`
|
|
|
|
### ⚠️ IMPORTANT : Prérequis
|
|
|
|
1. **Colonnes V3** : La base doit avoir toutes les colonnes V3 (`watermarked_s3_key`, `watermarked_at`, `zip_hash`, `zip_s3_key`, `zip_size`, `proof_data`)
|
|
2. **Prisma Client** : Le client Prisma doit être généré avec le bon schéma
|
|
3. **Connexion BDD** : Les scripts utilisent `DATABASE_URL` (configurée sur le serveur ou via `.env.<env>`)
|
|
|
|
### Workflow Recommandé
|
|
|
|
1. **Audit initial** :
|
|
|
|
```bash
|
|
ENV=prod npm run anchorage:audit
|
|
```
|
|
|
|
2. **Test avec dry-run** :
|
|
|
|
```bash
|
|
ENV=prod npm run anchorage -- --all-archived --batch=1 --dry-run
|
|
```
|
|
|
|
3. **Ancrage réel** :
|
|
|
|
```bash
|
|
ENV=prod npm run anchorage -- --all-archived --batch=5
|
|
```
|
|
|
|
---
|
|
|
|
## 7. Troubleshooting
|
|
|
|
### Certificats Manquants dans le ZIP
|
|
|
|
**Symptôme** : Lors de la validation d'un document, le document apparaît comme validé, mais le certificat d'ancrage n'est pas présent dans le ZIP téléchargé.
|
|
|
|
**Root Cause** :
|
|
|
|
1. Recherche par hash uniquement (peut échouer)
|
|
2. Pas de vérification du statut avant génération
|
|
|
|
**Solution** :
|
|
|
|
1. Recherche prioritaire par `document_uid` (plus fiable)
|
|
2. Fallback par hash si nécessaire
|
|
3. Vérification du statut (`status === VERIFIED_ON_CHAIN`) avant génération
|
|
|
|
### Timing et Synchronisation
|
|
|
|
**Scénario typique** :
|
|
|
|
1. **T0** : Document validé → Ancrage lancé en arrière-plan
|
|
2. **T0+2s** : Ancrage créé avec `status = ATTEMPTING`
|
|
3. **T0+5s** : Transaction Bitcoin confirmée → `status = VERIFIED_ON_CHAIN` (après 6 confirmations)
|
|
4. **T0+10s** : Utilisateur télécharge le ZIP → Certificat inclus ✅
|
|
|
|
**Cas limite** : Si l'utilisateur télécharge le ZIP **immédiatement après validation** (avant que l'ancrage soit vérifié) :
|
|
|
|
- ⚠️ L'ancrage peut être en statut `ATTEMPTING` ou `QUEUED`
|
|
- ⚠️ Le certificat **ne sera pas inclus** dans le ZIP
|
|
- ✅ L'utilisateur peut **relancer le téléchargement** plus tard pour obtenir le certificat
|
|
|
|
### Fichiers Sans Clé de Chiffrement (.expired)
|
|
|
|
**Contexte** : Les dumps de base de données provenant de versions antérieures peuvent contenir des fichiers avec `key = null` (clé de chiffrement perdue).
|
|
|
|
**Solution implémentée** :
|
|
|
|
- `FilesService.download()` : Retourne fichier vide `.expired` si `key = null`
|
|
- `WatermarkService.addWatermarkAndUpload()` : Upload fichier vide `.expired` sur IPFS
|
|
- `DocumentAnchorsService.anchorDocument()` : Ancrage avec hash du buffer vide
|
|
|
|
**Résultat** :
|
|
|
|
- ✅ Scripts d'ancrage ne crashent plus sur fichiers sans clé
|
|
- ✅ Fichiers `.expired` créés automatiquement
|
|
- ✅ Ancrage blockchain avec hash du buffer vide
|
|
- ⚠️ Utilisateur informé que fichier non récupérable
|
|
|
|
### Checklist de Vérification
|
|
|
|
Pour diagnostiquer un problème de certificat manquant dans un ZIP :
|
|
|
|
- [ ] Vérifier que le document est **validé** (`document_status === VALIDATED`)
|
|
- [ ] Vérifier qu'un ancrage existe pour ce document (`document_anchors` table)
|
|
- [ ] Vérifier le **statut de l'ancrage** (`status === VERIFIED_ON_CHAIN`)
|
|
- [ ] Vérifier les **logs backend** pour voir si l'ancrage a été trouvé
|
|
- [ ] Vérifier que `includeAnchors = true` lors de l'appel à `createZipFromFiles`
|
|
- [ ] Vérifier que le fichier n'est pas un `isNotaryFiles` (pas d'ancrage pour les fichiers notaire)
|
|
|
|
---
|
|
|
|
## 8. Références
|
|
|
|
### Documentation Détaillée
|
|
|
|
- **Architecture V3** : `docs/ANCRAGE_V3_ARCHITECTURE.md` - Architecture complète V3
|
|
- **Certificats et ZIP** : `docs/ANCRAGE_CERTIFICATS_ZIP.md` - Génération certificats et ZIP
|
|
- **Scripts** : `docs/SCRIPTS.md` - Scripts d'audit et d'ancrage
|
|
- **Statuts** : `docs/ANCHOR_STATUS_VERIFICATION.md` - Vérification des statuts d'ancrage
|
|
- **Séquences de traitement** : `docs/DOCUMENT_PROCESSING_SEQUENCES_V2.md` - Séquence complète upload/ancrage
|
|
|
|
### Services Backend
|
|
|
|
- **WatermarkService** : `lecoffre-back-main/src/services/common/WatermarkService/WatermarkService.ts`
|
|
- **DocumentAnchorsService** : `lecoffre-back-main/src/services/notary/DocumentAnchorsService/DocumentAnchorsService.ts`
|
|
- **OfficeFolderAnchorsService** : `lecoffre-back-main/src/services/notary/OfficeFolderAnchorsService/OfficeFolderAnchorsService.ts`
|
|
- **ProofDataService** : `lecoffre-back-main/src/services/notary/ProofDataService/ProofDataService.ts`
|
|
- **BitcoinSignetService** : `lecoffre-back-main/src/services/common/BitcoinSignetService/BitcoinSignetService.ts`
|
|
- **AnchorCertificateService** : `lecoffre-back-main/src/services/notary/AnchorCertificateService/AnchorCertificateService.ts`
|
|
- **ZipService** : `lecoffre-back-main/src/services/common/ZipService/ZipService.ts`
|
|
|
|
### Controllers
|
|
|
|
- **DocumentsController** : `lecoffre-back-main/src/app/api/notary/DocumentsController.ts`
|
|
- **FilesController (Notary)** : `lecoffre-back-main/src/app/api/notary/FilesController.ts`
|
|
- **FilesController (Customer)** : `lecoffre-back-main/src/app/api/customer/FilesController.ts`
|
|
- **PublicAnchorVerificationController** : `lecoffre-back-main/src/app/api/public/PublicAnchorVerificationController.ts`
|
|
|
|
### Scripts
|
|
|
|
- **Audit** : `lecoffre-back-main/src/scripts/audit-missing-anchors.ts`
|
|
- **Ancrage dossiers** : `lecoffre-back-main/src/scripts/anchor-existing-folders-v3.ts`
|
|
- **Réancrage** : `lecoffre-back-main/src/scripts/reanchor-documents.ts`
|
|
- **Nettoyage** : `lecoffre-back-main/src/scripts/clean-incomplete-folder-anchors.ts`
|
|
|
|
### Frontend
|
|
|
|
- **Page vérification** : `lecoffre-front-main/src/pages/verify-document.tsx`
|
|
- **Composant AnchorBadge** : `lecoffre-front-main/src/front/Components/DesignSystem/AnchorBadge/`
|
|
|
|
---
|
|
|
|
**Dernière mise à jour** : 2025-11-24
|
|
**Version** : 3.1.2
|