Aller au contenu

📘 Development Guide - ProbatioVault

Date: 10 novembre 2025 Version: 1.0.0 Auteur: ProbatioVault Team


📋 Table des matières

  1. Architecture du projet
  2. Structure des dossiers
  3. Conventions de nommage
  4. Standards de qualité
  5. Pipeline CI/CD
  6. Tests et couverture
  7. Sécurité

🏗️ Architecture du projet

Principes architecturaux

ProbatioVault suit une architecture modulaire et scalable basée sur les principes suivants :

  1. Separation of Concerns (SoC) - Séparation claire entre couches
  2. Domain-Driven Design (DDD) - Organisation par domaine métier
  3. Single Responsibility - Une responsabilité par module
  4. Type Safety - TypeScript strict mode activé

Couches de l'application

┌─────────────────────────────────────┐
│         UI Layer (Screens)          │ ← React Native Components
├─────────────────────────────────────┤
│      Presentation Layer (Hooks)     │ ← Business Logic
├─────────────────────────────────────┤
│    State Management Layer (Stores)  │ ← Zustand + Persistence
├─────────────────────────────────────┤
│     Services Layer (Services)       │ ← Crypto, API, Storage
├─────────────────────────────────────┤
│    Infrastructure Layer (Utils)     │ ← Helpers, Constants
└─────────────────────────────────────┘

📁 Structure des dossiers

Structure cible (conforme PD-96)

src/
├── components/                 # Composants réutilisables
│   ├── common/                # Composants génériques (UI)
│   │   ├── Button.tsx
│   │   ├── Input.tsx
│   │   ├── HeaderLeft.tsx
│   │   └── ProgressBar.tsx
│   ├── vault/                 # Composants métier coffre-fort
│   │   ├── DocumentRow.tsx
│   │   ├── FolderCard.tsx
│   │   └── ProofBadge.tsx
│   ├── security/              # Composants sécurité
│   │   ├── BiometricPrompt.tsx
│   │   ├── PinInput.tsx
│   │   └── SecurityIndicator.tsx
│   └── index.ts               # Export centralisé
├── screens/                   # Écrans de l'application
│   ├── auth/                  # Authentification
│   │   ├── LoginScreen.tsx
│   │   ├── RegisterScreen.tsx
│   │   └── BiometricSetupScreen.tsx
│   ├── vault/                 # Coffre-fort
│   │   ├── HomeScreen.tsx
│   │   ├── FolderDetailScreen.tsx
│   │   ├── CreateFolderScreen.tsx
│   │   ├── UploadDocumentScreen.tsx
│   │   ├── DocumentProofScreen.tsx
│   │   └── MediaPreviewScreen.tsx
│   ├── settings/              # Paramètres
│   │   ├── SettingsScreen.tsx
│   │   ├── SecuritySettingsScreen.tsx
│   │   └── AboutScreen.tsx
│   └── index.ts               # Export centralisé
├── hooks/                     # Custom React Hooks
│   ├── useAuth.ts            # Authentification
│   ├── useVault.ts           # Gestion coffre-fort
│   ├── useBiometric.ts       # Authentification biométrique
│   └── index.ts              # Export centralisé
├── services/                  # Services métier
│   ├── crypto.ts             # Chiffrement (AES-256-GCM)
│   ├── storage.ts            # FileSystem + SecureStore
│   ├── api.ts                # Backend API client
│   └── index.ts              # Export centralisé
├── store/                     # State Management (Zustand)
│   ├── useAuthStore.ts       # Authentification
│   ├── useVaultStore.ts      # Coffre-fort unifié
│   ├── useAppStore.ts        # État global app
│   └── index.ts              # Export centralisé
├── navigation/                # Navigation
│   ├── AppNavigator.tsx      # Navigateur principal
│   └── types.ts              # Types navigation
├── types/                     # Types TypeScript
│   ├── document.ts
│   ├── folder.ts
│   ├── proof.ts
│   └── index.ts              # Export centralisé
├── constants/                 # Constantes
│   ├── categories.ts
│   ├── subcases.ts
│   └── colors.ts
├── utils/                     # Utilitaires
│   ├── telemetry.ts          # Télémétrie
│   ├── documentStatus.ts     # Statuts documents
│   └── validators.ts         # Validateurs
├── i18n/                      # Internationalisation
│   ├── index.ts
│   ├── fr/
│   │   └── translation.json
│   └── en/
│       └── translation.json
├── context/                   # React Context (legacy)
│   └── AuthContext.tsx       # À migrer vers hooks/useAuth.ts
├── __tests__/                 # Tests unitaires
│   ├── useVaultStore.test.ts
│   ├── useAuth.test.ts
│   └── crypto.test.ts
└── __mocks__/                 # Mocks Jest
    ├── expo-file-system.ts
    ├── expo-secure-store.ts
    └── @react-native-async-storage/

🏷️ Conventions de nommage

Fichiers

Type Convention Exemple
Composants React PascalCase.tsx DocumentRow.tsx
Screens PascalCase.tsx + "Screen" FolderDetailScreen.tsx
Hooks camelCase.ts + "use" prefix useAuth.ts, useVault.ts
Services camelCase.ts crypto.ts, storage.ts
Stores camelCase.ts + "Store" suffix useVaultStore.ts
Types camelCase.ts document.ts, folder.ts
Utils camelCase.ts telemetry.ts, validators.ts
Tests camelCase.test.ts useVaultStore.test.ts
Mocks kebab-case.ts expo-file-system.ts

Variables et fonctions

// ✅ CORRECT

// Constants - SCREAMING_SNAKE_CASE
const MAX_FILE_SIZE = 10 * 1024 * 1024;
const ENCRYPTION_KEY = "pv-vault-key";

// Variables - camelCase
const documentId = "doc123";
const folderName = "Contrats";

// Functions - camelCase (verbe d'action)
function addDocument(doc: Document): void {}
function deleteFolder(id: string): Promise<void> {}

// React Components - PascalCase
const DocumentRow: React.FC<Props> = ({ document }) => {};

// Types/Interfaces - PascalCase
interface Document {
  id: string;
  name: string;
}

type DocumentStatus = "pending" | "local" | "cloud";

// Enum - PascalCase pour le type, SCREAMING_SNAKE_CASE pour les valeurs
enum FileType {
  PDF = "application/pdf",
  IMAGE = "image/jpeg",
}

Nommage des fonctions

Préfixe Usage Exemple
get Récupération synchrone getDocumentById()
fetch Récupération asynchrone fetchDocuments()
add Ajout addFolder()
update Mise à jour updateDocument()
delete Suppression deleteFolder()
remove Retrait (sans suppression physique) removeFromList()
is Booléen (état) isAuthenticated()
has Booléen (possession) hasProof()
can Booléen (permission) canUpload()
handle Gestionnaire d'événement handlePress()
on Callback onDocumentAdded()
use Custom Hook useAuth(), useVault()

✅ Standards de qualité

PD-96 : Exigences de couverture

Coverage Thresholds:
  statements: 70%    # Minimum 70% des instructions testées
  branches: 60%      # Minimum 60% des branches testées
  functions: 70%     # Minimum 70% des fonctions testées
  lines: 70%         # Minimum 70% des lignes testées

Configuration Jest (jest.config.js):

// TODO(PD-96): enforce coverageThreshold >= 70% once test suite is complete.
coverageThreshold: {
  global: {
    statements: 70,
    branches: 60,
    functions: 70,
    lines: 70
  }
}

ESLint Rules

Configuration : .eslintrc.js

Règles critiques :

  • sonarjs/no-unused-vars - Pas de variable inutilisée
  • sonarjs/no-duplicate-string - Pas de duplication de chaînes
  • sonarjs/cognitive-complexity - Complexité max 15
  • sonarjs/no-hardcoded-passwords - Pas de mot de passe en dur
  • @typescript-eslint/no-explicit-any - Pas de any
  • @typescript-eslint/strict-boolean-expressions - Booléens stricts

TypeScript Strict Mode

Configuration : tsconfig.json

{
  "compilerOptions": {
    "strict": true,
    "noImplicitAny": true,
    "strictNullChecks": true,
    "strictFunctionTypes": true,
    "strictBindCallApply": true,
    "strictPropertyInitialization": true,
    "noImplicitThis": true,
    "alwaysStrict": true
  }
}

🔄 Pipeline CI/CD

Étapes CI (conforme PD-96)

# .gitlab-ci.yml ou .github/workflows/ci.yml

stages:
  - install
  - lint
  - test
  - build
  - deploy

# 1. Installation des dépendances
install:
  stage: install
  script:
    - npm ci
  cache:
    paths:
      - node_modules/

# 2. Vérification qualité code
lint:
  stage: lint
  script:
    - npm run lint              # ESLint
    - npm run typecheck         # TypeScript
  dependencies:
    - install

# 3. Tests unitaires + couverture
test:
  stage: test
  script:
    - npm run test:ci           # Jest avec coverage
  coverage: '/Lines\s*:\s*(\d+\.\d+)%/'
  artifacts:
    reports:
      coverage_report:
        coverage_format: cobertura
        path: coverage/cobertura-coverage.xml
    paths:
      - coverage/
  dependencies:
    - install
  # ❌ FAIL si coverage < 70% (PD-96)
  rules:
    - if: '$CI_COMMIT_BRANCH == "main"'
      when: always

# 4. SonarQube Analysis
sonarqube:
  stage: test
  script:
    - sonar-scanner
      -Dsonar.projectKey=probatiovault-app
      -Dsonar.sources=src
      -Dsonar.tests=src/__tests__
      -Dsonar.javascript.lcov.reportPaths=coverage/lcov.info
      -Dsonar.coverage.exclusions=**/*.test.ts,**/__mocks__/**
  dependencies:
    - test
  only:
    - main
    - develop

# 5. Build de production
build:
  stage: build
  script:
    - npx expo export --platform all
    - npx eas build --platform all --non-interactive
  artifacts:
    paths:
      - dist/
  only:
    - main
    - tags

# 6. Déploiement
deploy:staging:
  stage: deploy
  script:
    - npx eas update --branch staging
  only:
    - develop

deploy:production:
  stage: deploy
  script:
    - npx eas update --branch production
  only:
    - main

Scripts package.json requis

{
  "scripts": {
    // Développement
    "start": "expo start",
    "android": "expo start --android",
    "ios": "expo start --ios",
    "web": "expo start --web",

    // Qualité code
    "lint": "eslint 'src/**/*.{js,jsx,ts,tsx}'",
    "lint:fix": "eslint 'src/**/*.{js,jsx,ts,tsx}' --fix",
    "typecheck": "tsc --noEmit",
    "format": "prettier --write 'src/**/*.{js,jsx,ts,tsx,json,md}'",

    // Tests
    "test": "jest --watch",
    "test:ci": "cross-env EXPO_OS=ios jest --ci --maxWorkers=2",
    "test:coverage": "jest --coverage",

    // Build
    "build:android": "eas build --platform android",
    "build:ios": "eas build --platform ios",
    "build:all": "eas build --platform all"
  }
}

🧪 Tests et couverture

Stratégie de tests

Tests Pyramid (PD-96):

                  /\
                 /  \        E2E Tests (10%)
                /----\       - Critical user flows
               /      \
              /--------\     Integration Tests (20%)
             /          \    - API + Store + UI
            /------------\
           /              \  Unit Tests (70%)
          /________________\ - Services, Hooks, Utils

Organisation des tests

src/__tests__/
├── unit/                       # Tests unitaires
│   ├── stores/
│   │   ├── useVaultStore.test.ts      ✅ 25 tests
│   │   ├── useAuthStore.test.ts       🔄 À créer
│   │   └── useAppStore.test.ts        🔄 À créer
│   ├── services/
│   │   ├── crypto.test.ts             🔄 À créer (PD-96)
│   │   ├── storage.test.ts            🔄 À créer (PD-96)
│   │   └── api.test.ts                🔄 À créer (PD-96)
│   ├── hooks/
│   │   ├── useAuth.test.ts            🔄 À créer (PD-96)
│   │   ├── useVault.test.ts           🔄 À créer (PD-96)
│   │   └── useBiometric.test.ts       🔄 À créer (PD-96)
│   └── utils/
│       ├── validators.test.ts         🔄 À créer
│       └── telemetry.test.ts          🔄 À créer
├── integration/                # Tests d'intégration
│   ├── document-upload.test.ts        🔄 À créer
│   └── folder-management.test.ts      🔄 À créer
└── e2e/                        # Tests end-to-end
    └── critical-flows.test.ts         🔄 À créer

Couverture actuelle vs objectif PD-96

Métrique Actuel Objectif PD-96 Écart
Statements 23.42% 70% -46.58%
Branches 13.14% 60% -46.86%
Functions 28.11% 70% -41.89%
Lines 22.73% 70% -47.27%

Priorités pour atteindre 70% :

  1. ✅ useVaultStore.ts (fait - 25 tests)
  2. 🔄 services/crypto.ts (~40 tests estimés)
  3. 🔄 hooks/useAuth.ts (~20 tests estimés)
  4. 🔄 hooks/useVault.ts (~15 tests estimés)
  5. 🔄 services/storage.ts (~15 tests estimés)

Commandes de test

# Mode watch (développement)
npm test

# CI mode (avec coverage)
npm run test:ci

# Coverage HTML report
npm run test:coverage
open coverage/lcov-report/index.html

# Test un fichier spécifique
npm test -- useVaultStore.test.ts

# Test avec verbose
npm test -- --verbose

# Update snapshots
npm test -- -u

🔒 Sécurité

Standards de sécurité

Chiffrement :

  • ✅ AES-256-GCM pour fichiers (authentifié, empêche tampering)
  • ✅ AES-256-CBC pour données JSON store (rétrocompatibilité V2)
  • ✅ PBKDF2-SHA256 100k itérations pour Master Key
  • ✅ Salt 32 bytes, IV 12 bytes (GCM) / 16 bytes (CBC)

Stockage :

  • ✅ SecureStore pour données sensibles (tokens, passwords)
  • ✅ AsyncStorage chiffré pour état Zustand
  • ✅ Fichiers chiffrés dans FileSystem local

Authentification :

  • ✅ Master Key jamais en clair
  • ✅ Biométrie avec fallback PIN
  • ✅ JWT tokens avec refresh (backend)

Audit de sécurité

# Audit npm dependencies
npm audit

# Fix vulnérabilités automatiquement
npm audit fix

# Audit avec rapport détaillé
npm audit --json > security-audit.json

# Vérification hardcoded secrets (via ESLint)
npm run lint

Checklist sécurité

  • Pas de secrets hardcodés (cf. ESLint sonarjs/no-hardcoded-passwords)
  • Pas de console.log de données sensibles en production
  • HTTPS uniquement pour API calls
  • Validation des inputs utilisateur
  • Sanitization des URLs
  • Gestion des erreurs sans leaks d'info
  • Timeouts sur toutes les requêtes réseau
  • Rate limiting côté client

📚 Documentation additionnelle


🎯 Checklist avant merge (Pull Request)

Qualité code

  • ESLint 0 erreur : npm run lint
  • TypeScript 0 erreur : npm run typecheck
  • Code formaté : npm run format

Tests

  • Tous les tests passent : npm run test:ci
  • Nouveaux tests pour nouvelle feature
  • Coverage ≥ 70% (ou justification si < 70%)

Documentation

  • README.md mis à jour si nécessaire
  • Commentaires JSDoc pour fonctions publiques
  • CHANGELOG.md mis à jour

Sécurité

  • Pas de secrets hardcodés
  • Audit npm : npm audit clean
  • Revue de code sécurité (peer review)

CI/CD

  • Pipeline CI passe ✅
  • SonarQube Quality Gate OK
  • Build de production réussit

🚀 Workflows recommandés

Workflow Git

# 1. Créer une branche feature
git checkout -b feature/PD-123-add-document-preview

# 2. Développer + tests
npm test -- --watch

# 3. Vérifier qualité
npm run lint
npm run typecheck
npm run test:ci

# 4. Commit (conventional commits)
git add .
git commit -m "feat(vault): add document preview with zoom

- Add DocumentPreviewScreen with pinch-to-zoom
- Support PDF, images, videos
- Add tests for preview component

Closes PD-123"

# 5. Push et créer PR
git push -u origin feature/PD-123-add-document-preview

# 6. Attendre review + CI ✅
# 7. Merge dans develop/main

Conventional Commits

<type>(<scope>): <subject>

<body>

<footer>

Types :

  • feat: Nouvelle fonctionnalité
  • fix: Correction de bug
  • refactor: Refactoring (pas de changement fonctionnel)
  • test: Ajout/modification de tests
  • docs: Documentation
  • style: Formatage (prettier, etc.)
  • perf: Amélioration de performance
  • chore: Tâches de maintenance

Exemples :

feat(vault): add cascade delete for folders
fix(crypto): handle empty file encryption
refactor(store): merge 3 stores into useVaultStore
test(vault): add 25 tests for useVaultStore
docs(readme): update folder structure

✉️ Contact

Questions sur le guide : support@probatiovault.com Documentation : https://probatiovault.com/docs CI/CD : https://gitlab.com/probatiovault/app


"Code quality is not an act, it's a habit." — Aristotle