Metadata-Version: 2.4
Name: sahges-sdk
Version: 0.1.13
Summary: SDK Python officiel de l'écosystème SAHGES
Author-email: SAHGES <floriano.gomez@bj.sanlamallianz.com>
License: MIT
Project-URL: Source, https://gitlab.com/florianogomez/sahges-sdk.git
Project-URL: Homepage, https://gitlab.com/florianogomez/sahges-sdk
Project-URL: Documentation, https://gitlab.com/florianogomez/sahges-sdk/-/blob/main/readme.md
Project-URL: Changelog, https://gitlab.com/florianogomez/sahges-sdk/-/blob/main/CHANGELOG.md
Project-URL: Bug Tracker, https://gitlab.com/florianogomez/sahges-sdk/-/issues
Keywords: sahges,sdk,api,authentication,documents
Classifier: Development Status :: 4 - Beta
Classifier: Intended Audience :: Developers
Classifier: License :: OSI Approved :: MIT License
Classifier: Programming Language :: Python :: 3
Classifier: Programming Language :: Python :: 3.10
Classifier: Programming Language :: Python :: 3.11
Classifier: Programming Language :: Python :: 3.12
Classifier: Topic :: Software Development :: Libraries :: Python Modules
Requires-Python: >=3.10
Description-Content-Type: text/markdown
Requires-Dist: httpx>=0.27
Requires-Dist: marshmallow>=3.20
Requires-Dist: marshmallow-dataclass>=8.6
Requires-Dist: python-dotenv>=1.0.0
Provides-Extra: dev
Requires-Dist: pytest>=7.4; extra == "dev"
Requires-Dist: pytest-cov>=4.1; extra == "dev"
Requires-Dist: pytest-asyncio>=0.21; extra == "dev"
Requires-Dist: black>=23.0; extra == "dev"
Requires-Dist: ruff>=0.1; extra == "dev"
Requires-Dist: mypy>=1.5; extra == "dev"

# SAHGES SDK

SDK Python officiel pour l'écosystème SAHGES. Facilite l'intégration avec les services SAHGES via une interface Python simple et robuste avec types stricts.

[![Python Version](https://img.shields.io/badge/python-3.10%2B-blue)](https://www.python.org/downloads/)
[![License](https://img.shields.io/badge/license-MIT-green)](LICENSE)

## 📋 Prérequis

- Python 3.10 ou supérieur
- pip pour l'installation des dépendances

## 🚀 Installation

```bash
pip install sahges-sdk
```

Ou depuis les sources :

```bash
git clone https://gitlab.com/florianogomez/sahges-sdk.git
cd sahges-sdk
pip install -e .
```

## 🎯 Démarrage rapide

### Authentification

```python
from sahges_sdk.auth import SahgesAuthClient

# Initialiser le client
client = SahgesAuthClient(
    client_id="votre_client_id",
    client_secret="votre_client_secret"
)

# Se connecter - retourne un objet SahgesLoginResponse
response = client.login(payload={
    "credential": "user@example.com",
    "password": "mot_de_passe"
})

# ✅ Accès par attribut (dataclass)
print(f"Token: {response.access_token}")
print(f"Email: {response.user.email}")
print(f"Nom: {response.user.first_name} {response.user.last_name}")
print(f"Organisation: {response.user.organization.name}")
print(f"Rôle: {response.user.role}")
```

### Gestion de documents

```python
from sahges_sdk.docs import SahgesDocsClient
from pathlib import Path

# Initialiser le client
docs = SahgesDocsClient(
    client_id="votre_client_id",
    client_secret="votre_client_secret"
)

# Uploader un document - retourne un objet SahgesDocument
document = docs.create(
    title="Mon document",
    file_path=Path("document.pdf"),
    visibility="ORGANIZATION",
    status="DRAFT"
)

# ✅ Accès par attribut
print(f"ID: {document.id}")
print(f"Titre: {document.title}")
print(f"Taille: {document.file_size} bytes")
print(f"Format: {document.file_format}")
print(f"Créé le: {document.created_at}")

# Lister les documents - retourne List[SahgesDocumentListItem]
documents = docs.list(payload={"status": "VALIDATED"})

for doc in documents:
    print(f"- {doc.title} ({doc.file_format})")
```

## ⚙️ Configuration

### Variables d'environnement

Créez un fichier `.env` :

```env
# Credentials API (obligatoire)
SAHGES_CLIENT_ID=votre_client_id
SAHGES_CLIENT_SECRET=votre_client_secret

# URLs des services (optionnel)
SAHGES_AUTHENTICATION_BASE_URL=https://api.sahges.com
SAHGES_DOCS_BASE_URL=https://docs.sahges.com
```

### Utilisation avec .env

```python
import os
from dotenv import load_dotenv
from sahges_sdk.auth import SahgesAuthClient

load_dotenv()

client = SahgesAuthClient(
    client_id=os.getenv('SAHGES_CLIENT_ID'),
    client_secret=os.getenv('SAHGES_CLIENT_SECRET')
)
```

## 📖 Guide d'utilisation

### Module Auth - Authentification

Le module Auth fournit toutes les fonctionnalités d'authentification et de gestion de session.

#### 1. Connexion (Login)

```python
from sahges_sdk.auth import SahgesAuthClient

client = SahgesAuthClient(
    client_id="votre_client_id",
    client_secret="votre_client_secret"
)

# Se connecter
response = client.login(payload={
    "credential": "user@example.com",  # Email ou téléphone
    "password": "votre_mot_de_passe"
})

# SahgesLoginResponse est une dataclass avec:
# - access_token: str
# - refresh_token: Optional[str]
# - user: AuthUser

print(f"Token d'accès: {response.access_token}")
print(f"Token de rafraîchissement: {response.refresh_token}")
print(f"Utilisateur: {response.user.email}")
```

#### 2. Rafraîchissement de token (Refresh)

```python
# Rafraîchir le token sans redemander le mot de passe
new_tokens = client.refresh(payload={
    "refresh_token": response.refresh_token
})

# SahgesRefreshResponse est identique à SahgesLoginResponse
print(f"Nouveau token: {new_tokens.access_token}")
print(f"Utilisateur: {new_tokens.user.email}")  # Inclus dans la réponse
```

#### 3. Introspection

```python
# Obtenir les informations de l'utilisateur connecté
user = client.introspect(access_token=response.access_token)

# AuthUser est une dataclass avec:
# - id: UUID
# - email: str
# - first_name: str
# - last_name: str
# - phone: Optional[str]
# - is_active: bool
# - is_using_default_password: bool
# - role: SahgesAuthUserRoleEnum (USER, ADMIN, SUPERADMIN)
# - organization: SahgesAuthOrganization

print(f"ID: {user.id}")
print(f"Email: {user.email}")
print(f"Nom complet: {user.first_name} {user.last_name}")
print(f"Téléphone: {user.phone}")
print(f"Actif: {user.is_active}")
print(f"Rôle: {user.role}")
print(f"Organisation: {user.organization.name}")
print(f"Type org: {user.organization.type}")
```

#### 4. Déconnexion (Logout)

```python
# Se déconnecter - retourne True en cas de succès
result = client.logout(access_token=response.access_token)

print(result)  # True

# En cas d'erreur, lève SahgesAuthenticationError
```

#### 5. Mot de passe oublié (Forgot Password)

```python
# Demander un lien de réinitialisation par email
response = client.forgot_password(payload={
    "credential": "user@example.com"  # Email ou téléphone
})

# SahgesForgotPasswordResponse contient:
# - message: str
print(response.message)  # "Email de réinitialisation envoyé"
```

#### 6. Valider le token de réinitialisation

```python
# Vérifier que le token reçu par email est valide
token = "token_reçu_par_email"

challenge = client.reset_password_challenge(token=token)

# SahgesResetPasswordChallengeResponse contient:
# - valid: bool
# - message: Optional[str]

if challenge.valid:
    print("Token valide, vous pouvez réinitialiser")
else:
    print(f"Token invalide: {challenge.message}")
```

#### 7. Réinitialiser le mot de passe

```python
# Changer le mot de passe avec le token valide
result = client.reset_password(payload={
    "token": token,
    "new_password": "nouveau_mot_de_passe_securise",
    "new_password_confirmation": "nouveau_mot_de_passe_securise"
})

# SahgesResetPasswordResponse contient:
# - user: SahgesResetPasswordUser (version simplifiée)
# - redirect_url: Optional[str]

print(f"Mot de passe changé pour: {result.user.id}")
if result.redirect_url:
    print(f"Redirection vers: {result.redirect_url}")
```

#### Cycle de vie complet d'une session

```python
from sahges_sdk.auth import SahgesAuthClient

client = SahgesAuthClient(client_id="...", client_secret="...")

# 1. Connexion
login = client.login({"credential": "user@example.com", "password": "pass"})
access_token = login.access_token
refresh_token = login.refresh_token

# 2. Utiliser le token pour les requêtes...
user = client.introspect(access_token=access_token)
print(f"Connecté: {user.email}")

# 3. Rafraîchir avant expiration
refreshed = client.refresh({"refresh_token": refresh_token})
access_token = refreshed.access_token
refresh_token = refreshed.refresh_token

# 4. Déconnexion
client.logout(access_token=access_token)
```

### Module Docs - Gestion documentaire

Le module Docs gère l'upload, le stockage et le partage de documents avec traitement IA.

#### 1. Créer un document (Upload)

```python
from sahges_sdk.docs import SahgesDocsClient
from pathlib import Path

docs = SahgesDocsClient(client_id="...", client_secret="...")

# Créer avec upload de fichier
document = docs.create(
    title="Contrat client XYZ",
    file_path=Path("/path/to/contrat.pdf"),
    description="Contrat commercial 2025",
    visibility="ORGANIZATION",  # PRIVATE, ORGANIZATION, PUBLIC
    status="DRAFT",              # DRAFT, PENDING, VALIDATED, ARCHIVED
    category="legal",
    tags=["contrat", "2025", "client-xyz"]
)

# SahgesDocument est une dataclass complète avec:
# - id: UUID
# - title: str
# - visibility: SahgesDocumentVisibilityEnum
# - status: SahgesDocumentStatusEnum
# - file_name: str
# - file_size: int
# - file_mime_type: str
# - file_format: SahgesDocumentFileFormatEnum
# - sha256_hash: str
# - preview_generated: bool
# - created_at: datetime
# - updated_at: datetime
# + 15+ champs optionnels (description, tags, ocr_text, ai_summary, etc.)

print(f"SahgesDocument créé: {document.id}")
print(f"Fichier: {document.file_name} ({document.file_size} bytes)")
print(f"Format: {document.file_format}")
print(f"Hash SHA-256: {document.sha256_hash}")

# Vérifier les résultats du traitement IA
if document.ocr_text:
    print(f"Texte OCR disponible: {len(document.ocr_text)} caractères")
if document.ai_summary:
    print(f"Résumé IA: {document.ai_summary}")
if document.ai_metadata:
    print(f"Métadonnées IA: {document.ai_metadata}")
```

#### 2. Lister les documents

```python
# Liste simple - retourne List[SahgesDocumentListItem]
documents = docs.list(payload={})

for doc in documents:
    # SahgesDocumentListItem est une version simplifiée
    print(f"- {doc.title}")
    print(f"  ID: {doc.id}")
    print(f"  Format: {doc.file_format}")
    print(f"  Taille: {doc.file_size} bytes")
    print(f"  Créé: {doc.created_at}")

# Avec filtres
documents = docs.list(payload={
    "page": 1,
    "search": "contrat",           # Recherche textuelle
    "visibility": "ORGANIZATION",   # Filtre par visibilité
    "status": "VALIDATED",          # Filtre par statut
    "category": "legal",            # Filtre par catégorie
    "owner_only": True,             # Mes documents uniquement
    "shared_with_me": False         # Exclure documents partagés
})

print(f"Trouvé {len(documents)} document(s)")
```

#### 3. Récupérer un document complet

```python
# Obtenir tous les détails d'un document
document = docs.find(payload={
    "document_id": "550e8400-e29b-41d4-a716-446655440000"
})

# SahgesDocument complet avec tous les champs
print(f"Titre: {document.title}")
print(f"Description: {document.description}")
print(f"Catégorie: {document.category}")
print(f"Tags: {document.tags}")
print(f"Propriétaire: {document.owner_auth_user_id}")
print(f"Organisation: {document.organization_id}")
print(f"Métadonnées: {document.document_metadata}")

# Traitement IA
if document.ocr_text:
    print(f"OCR: {document.ocr_text[:200]}...")
if document.audio_transcription:
    print(f"Transcription: {document.audio_transcription[:200]}...")
```

#### 4. Mettre à jour un document

```python
# Modifier les métadonnées d'un document
updated = docs.update(payload={
    "document_id": document.id,
    "title": "Nouveau titre",
    "description": "Nouvelle description",
    "status": "VALIDATED",
    "category": "finance",
    "tags": ["important", "2025"]
})

print(f"Mis à jour: {updated.title}")

# Changer uniquement la visibilité
updated = docs.update_visibility(payload={
    "document_id": document.id,
    "visibility": "PUBLIC"
})

print(f"Nouvelle visibilité: {updated.visibility}")
```

#### 5. Télécharger un document

```python
# Télécharger vers un fichier
docs.download(
    document_id=document.id,
    output_path="/path/to/save/document.pdf"
)

# Ou obtenir le contenu en bytes
file_bytes = docs.download(document_id=document.id)
# Traiter les bytes directement...
print(f"Téléchargé {len(file_bytes)} bytes")
```

#### 6. Supprimer un document

```python
# Supprimer définitivement
result = docs.delete(document_id=document.id)

print(result)  # True

# En cas d'erreur, lève SahgesRequestError
```

#### 7. Partager un document

```python
from datetime import datetime, timedelta

# Créer un partage avec permissions
share = docs.share_create(payload={
    "document_id": document.id,
    "shared_with_auth_user_id": "user-uuid-du-collegue",
    "permission": "VIEW",  # VIEW, EDIT, MANAGE
    "expires_at": datetime.now() + timedelta(days=30)
})

# SahgesDocumentShareCreateResponse contient:
# - id: UUID
# - document_id: UUID
# - shared_with_auth_user_id: UUID
# - shared_by_auth_user_id: UUID
# - permission: SahgesDocumentSharePermissionEnum
# - created_at: datetime
# - expires_at: Optional[datetime]

print(f"Partage créé: {share.id}")
print(f"Permission: {share.permission}")
print(f"Expire le: {share.expires_at}")
```

#### 8. Gérer les partages

```python
# Lister tous les partages d'un document
shares = docs.share_list(payload={
    "document_id": document.id
})

# List[SahgesDocumentShare]
for share in shares:
    print(f"Partagé avec: {share.shared_with.email}")
    print(f"  Permission: {share.permission}")
    print(f"  Par: {share.shared_by.email}")
    print(f"  Le: {share.created_at}")

# Révoquer un partage
if shares:
    result = docs.share_delete(payload={
        "document_id": document.id,
        "share_id": shares[0].id
    })
    print(result)  # True
```

#### 9. Endpoints clients (accès restreint)

Pour les applications tierces avec permissions limitées :

```python
# Liste (ORGANIZATION + PUBLIC uniquement)
documents = docs.clients_list(payload={
    "search": "facture",
    "category": "comptabilite"
})

# Créer (visibilité forcée à ORGANIZATION)
document = docs.clients_create(
    title="Facture janvier",
    file_path=Path("facture.pdf"),
    status="VALIDATED"
)

# Récupérer
doc = docs.clients_find(payload={"document_id": document.id})

# Télécharger
docs.clients_download(
    document_id=document.id,
    output_path="facture_downloaded.pdf"
)
```

## 🏗️ Architecture du SDK

### Structure des modules

```
src/sahges_sdk/
├── auth/              # Module d'authentification
│   ├── auth_client.py # Client avec 7 méthodes
│   ├── types.py       # Types dataclass (SahgesLoginResponse, etc.)
│   ├── routes.py      # Définition des routes API
│   └── [login|logout|introspect|reset_password]/
├── docs/              # Module de gestion documentaire
│   ├── docs_client.py # Client avec 10+ méthodes
│   ├── types.py       # Types dataclass (SahgesDocument, etc.)
│   ├── enums.py       # Énumérations (visibilité, statut...)
│   ├── routes.py      # Définition des routes API
│   └── [documents|shares|clients]/
├── base/              # Classes de base partagées
│   ├── client.py      # BaseSahgesApiClient (HTTP)
│   ├── endpoint.py    # Définition des endpoints
│   ├── decorators.py  # @sahges_endpoint pour validation
│   ├── enums.py       # SahgesAuthUserRoleEnum, etc.
│   ├── error.py       # Exceptions personnalisées
│   └── logger.py      # Configuration logging
└── config/            # Configuration centralisée
```

### Types et dataclasses

Le SDK utilise **marshmallow-dataclass** pour générer automatiquement :
- Des dataclasses Python avec types stricts
- Des schémas Marshmallow pour validation
- Autocomplétion IDE complète
- Type checking statique (mypy)

```python
# Exemple de type généré automatiquement
@dataclass
class SahgesLoginResponse:
    """Type pour la réponse de login"""
    access_token: str
    user: AuthUser
    refresh_token: Optional[str] = None
    
    class Meta:
        unknown = EXCLUDE  # Ignore les champs inconnus

# Utilisation
response = client.login(...)
print(response.access_token)  # ✅ Accès par attribut
print(response.user.email)    # ✅ Navigation type-safe
```

### Énumérations

```python
from sahges_sdk.base.enums import SahgesAuthUserRoleEnum, SahgesAuthOrganizationTypeEnum
from sahges_sdk.docs.enums import (
    SahgesDocumentVisibilityEnum,
    SahgesDocumentStatusEnum,
    SahgesDocumentSharePermissionEnum,
    SahgesDocumentFileFormatEnum
)

# Valeurs possibles
SahgesAuthUserRoleEnum       # USER, ADMIN, SUPERADMIN
SahgesAuthOrganizationTypeEnum  # INTERNAL, EXTERNAL

SahgesDocumentVisibilityEnum    # PRIVATE, ORGANIZATION, PUBLIC
SahgesDocumentStatusEnum        # DRAFT, PENDING, VALIDATED, ARCHIVED
SahgesDocumentSharePermissionEnum  # VIEW, EDIT, MANAGE
SahgesDocumentFileFormatEnum    # PDF, IMAGE, AUDIO, VIDEO, OFFICE, TEXT, OTHER
```

## 🔒 Gestion des erreurs

Le SDK fournit des exceptions spécifiques héritant de `SahgesError` :

```python
from sahges_sdk.base.error import (
    SahgesError,                 # Erreur de base
    SahgesClientConfigError,     # Configuration invalide
    SahgesRequestError,          # Erreur HTTP générale
    SahgesAuthenticationError,   # Erreur d'authentification (401/403)
    SahgesValidationError        # Erreur de validation de données
)

# Gestion complète des erreurs
try:
    response = client.login(payload={
        "credential": "user@example.com",
        "password": "wrong_password"
    })
    print(f"Connecté: {response.user.email}")
    
except SahgesAuthenticationError as e:
    # Erreur 401/403
    print(f"Authentification échouée: {e}")
    print(f"Status: {e.status_code}")
    print(f"Réponse: {e.response_data}")
    
except SahgesValidationError as e:
    # Données invalides
    print(f"Erreur de validation: {e}")
    
except SahgesRequestError as e:
    # Autre erreur HTTP (400, 404, 500...)
    print(f"Erreur HTTP: {e}")
    print(f"Status: {e.status_code}")
    
except SahgesClientConfigError as e:
    # client_id ou client_secret manquant
    print(f"Configuration incorrecte: {e}")
    
except SahgesError as e:
    # Erreur SAHGES générique
    print(f"Erreur SAHGES: {e}")
```

### Codes HTTP et exceptions

| Code HTTP | Exception | Description |
|-----------|-----------|-------------|
| 400 | `SahgesValidationError` | Données invalides |
| 401 | `SahgesAuthenticationError` | Non authentifié |
| 403 | `SahgesAuthenticationError` | Permissions insuffisantes |
| 404 | `SahgesRequestError` | Ressource introuvable |
| 429 | `SahgesRequestError` | Rate limit dépassé |
| 500 | `SahgesRequestError` | Erreur serveur |

## 🧪 Tests

Le projet comprend 33 tests unitaires + 16 tests manuels.

### Lancer les tests

```bash
# Tous les tests
pytest tests/ -v

# Tests avec couverture
pytest --cov=src tests/
pytest --cov=src --cov-report=html tests/

# Tests spécifiques
pytest tests/test_auth_login.py -v
pytest tests/test_auth_complete.py -v
pytest tests/test_docs_complete.py -v

# Tests manuels (nécessitent vraie API)
python tests/test_manual_login.py
python tests/test_manual_docs.py
```

### Utilisation du script manage.sh

```bash
# Lancer les tests
./manage.sh test

# Statistiques du projet
./manage.sh stats

# Publier sur PyPI
./manage.sh publish pypi
```

### Configuration pour tests

Créez un fichier `.env.test` :

```env
SAHGES_CLIENT_ID=test_client_id
SAHGES_CLIENT_SECRET=test_client_secret
SAHGES_TEST_EMAIL=test@example.com
SAHGES_TEST_PASSWORD=test_password
```

## 📝 Développement

### Installation développeur

```bash
git clone https://gitlab.com/florianogomez/sahges-sdk.git
cd sahges-sdk
python -m venv venv
source venv/bin/activate  # ou venv\Scripts\activate sur Windows
pip install -e ".[dev]"
```

### Dépendances

**Production:**
- `httpx>=0.27` - Client HTTP moderne
- `marshmallow>=3.20` - Validation et sérialisation
- `marshmallow-dataclass>=8.6` - Génération auto dataclass + schéma

**Développement:**
- `pytest` - Framework de tests
- `pytest-cov` - Couverture de code
- `python-dotenv` - Variables d'environnement

### Conventions de code

- **Python 3.10+** : Type hints modernes (`str | None` au lieu de `Union[str, None]`)
- **Dataclasses** : Pour tous les types de réponse
- **Marshmallow** : Pour validation des schémas
- **Docstrings** : Format Google pour toutes les fonctions publiques
- **Type hints** : Obligatoires partout
- **Exceptions** : Utiliser les exceptions spécifiques du SDK

### Ajouter une nouvelle fonctionnalité

Exemple pour le module Auth :

```python
# 1. Créer la fonction (src/sahges_sdk/auth/new_feature/feature.py)
from sahges_sdk.base.decorators import sahges_endpoint
from sahges_sdk.auth.routes import SahgesAuthenticationRoutes
from sahges_sdk.auth.types import NewFeatureResponse

@sahges_endpoint(
    request_schema=NewFeatureRequestSchema,
    response_schema=NewFeatureResponseSchema
)
def sahges_auth_new_feature(self, payload: dict) -> NewFeatureResponse:
    """Description de la fonctionnalité."""
    endpoint = SahgesAuthenticationRoutes.new_feature.value
    response = self.request(
        method=endpoint.method,
        path=endpoint.path,
        json=payload
    )
    return response

# 2. Définir le type de réponse (src/sahges_sdk/auth/types.py)
from marshmallow_dataclass import dataclass
from marshmallow import EXCLUDE

@dataclass
class NewFeatureResponse:
    """Type pour la réponse de new_feature"""
    result: str
    success: bool
    
    class Meta:
        unknown = EXCLUDE

# 3. Ajouter la route (src/sahges_sdk/auth/routes.py)
class SahgesAuthenticationRoutes(Enum):
    new_feature = Endpoint(
        path=f"/{BASE}/new-feature",
        method=HTTPMethod.POST
    )

# 4. Attacher au client (src/sahges_sdk/auth/auth_client.py)
from types import MethodType
from sahges_sdk.auth.types import NewFeatureResponse

class SahgesAuthClient(BaseSahgesApiClient):
    def __init__(self, client_id, client_secret):
        super().__init__(...)
        from sahges_sdk.auth.new_feature.feature import sahges_auth_new_feature
        self.new_feature = MethodType(sahges_auth_new_feature, self)
    
    def new_feature(self, payload: Dict[str, Any]) -> NewFeatureResponse:
        """
        Description publique de la fonctionnalité
        
        Args:
            payload: Paramètres de la requête
            
        Returns:
            NewFeatureResponse: Résultat de l'opération
        """
        # Implémentation liée dans __init__
        pass

# 5. Écrire les tests (tests/test_new_feature.py)
def test_new_feature_success():
    client = SahgesAuthClient("test_id", "test_secret")
    # Mock et assertions...
```

## 🤝 Contribution

Les contributions sont les bienvenues ! Processus :

1. Fork le projet
2. Créer une branche (`git checkout -b feature/AmazingFeature`)
3. Committer les changements (`git commit -m 'Add AmazingFeature'`)
4. Pusher vers la branche (`git push origin feature/AmazingFeature`)
5. Ouvrir une Pull Request

### Checklist avant PR

- [ ] Tests passent (`./manage.sh test`)
- [ ] Type hints ajoutés partout
- [ ] Docstrings présentes (format Google)
- [ ] Types dataclass pour les réponses
- [ ] Gestion d'erreurs appropriée
- [ ] CHANGELOG.md mis à jour

## 📄 Licence

Ce projet est sous licence MIT. Voir [LICENSE](LICENSE) pour détails.

## 📧 Contact

SAHGES - floriano.gomez@bj.sanlamallianz.com

Repository : https://gitlab.com/florianogomez/sahges-sdk

## 🔗 Liens utiles

- [SahgesDocumentation Auth complète](src/sahges_sdk/auth/readme.md)
- [SahgesDocumentation Docs complète](src/sahges_sdk/docs/readme.md)
- [Exemple d'utilisation](EXAMPLE_USAGE.py)
- [Guide de migration](MIGRATION_MARSHMALLOW_DATACLASS.md)
- [CHANGELOG](CHANGELOG.md)

## ❓ FAQ

### Comment obtenir des credentials API ?

Contactez floriano.gomez@bj.sanlamallianz.com pour obtenir `client_id` et `client_secret`.

### Quelle est la durée de vie des tokens ?

- **Access token** : 15 minutes
- **Refresh token** : 7 jours

### Pourquoi marshmallow-dataclass au lieu de TypedDict ?

- ✅ **Accès par attribut** : `response.access_token` au lieu de `response["access_token"]`
- ✅ **Validation automatique** : Les données invalides lèvent des erreurs
- ✅ **Autocomplétion IDE** : L'IDE connaît tous les attributs
- ✅ **Type checking** : mypy peut vérifier les types
- ✅ **Schémas réutilisables** : Partage avec le backend SAHGES

### Comment convertir un objet en dict ?

```python
from marshmallow_dataclass import class_schema

# Obtenir le schéma
schema = class_schema(type(response))()

# Convertir en dict
response_dict = schema.dump(response)
```

### Quels formats de fichiers sont supportés ?

Tous les formats. Traitement spécial pour :
- **PDF** : OCR et extraction de texte
- **Images** : OCR et analyse IA
- **Audio/Vidéo** : Transcription automatique
- **Office** : Conversion et prévisualisation

### Comment gérer les fichiers volumineux ?

Le système gère automatiquement les uploads en streaming. Vérifiez les limites avec votre administrateur.

### Puis-je utiliser le SDK en production ?

Oui, le SDK est conçu pour la production avec :
- Gestion d'erreurs robuste
- Logging approprié
- Validation stricte des données
- Tests complets (33 tests unitaires)
- Support Python 3.10+

## 📚 Exemples complets

### Workflow Auth + Docs combiné

```python
from sahges_sdk.auth import SahgesAuthClient
from sahges_sdk.docs import SahgesDocsClient
from pathlib import Path

# 1. Authentification
auth = SahgesAuthClient(client_id="...", client_secret="...")

login = auth.login({
    "credential": "user@example.com",
    "password": "password"
})

print(f"Connecté: {login.user.first_name} {login.user.last_name}")
print(f"Organisation: {login.user.organization.name}")
print(f"Rôle: {login.user.role}")

# 2. Gestion documentaire
docs = SahgesDocsClient(client_id="...", client_secret="...")

# Créer un document
doc = docs.create(
    title="Rapport mensuel",
    file_path=Path("rapport.pdf"),
    visibility="ORGANIZATION",
    status="VALIDATED",
    category="reporting",
    tags=["mensuel", "2025", "janvier"]
)

print(f"SahgesDocument créé: {doc.id}")
print(f"Fichier: {doc.file_name} ({doc.file_size} bytes)")

# Lister mes documents
my_docs = docs.list({"owner_only": True})
print(f"Vous avez {len(my_docs)} document(s)")

# Partager avec un collègue
from datetime import datetime, timedelta

share = docs.share_create({
    "document_id": doc.id,
    "shared_with_auth_user_id": "colleague-uuid",
    "permission": "VIEW",
    "expires_at": datetime.now() + timedelta(days=7)
})

print(f"Partagé avec permission {share.permission}")

# 3. Déconnexion
auth.logout(access_token=login.access_token)
print("Session terminée")
```

### Recherche et téléchargement

```python
from sahges_sdk.docs import SahgesDocsClient

docs = SahgesDocsClient(client_id="...", client_secret="...")

# Recherche avancée
results = docs.list({
    "search": "contrat client",
    "category": "legal",
    "status": "VALIDATED",
    "visibility": "ORGANIZATION"
})

print(f"Trouvé {len(results)} document(s)")

# Télécharger le premier résultat
if results:
    doc = results[0]
    print(f"Téléchargement de: {doc.title}")
    
    docs.download(
        document_id=doc.id,
        output_path=f"/tmp/{doc.file_name}"
    )
    
    print(f"Téléchargé dans /tmp/{doc.file_name}")
```

### Gestion des erreurs avancée

```python
from sahges_sdk.auth import SahgesAuthClient
from sahges_sdk.base.error import (
    SahgesAuthenticationError,
    SahgesValidationError,
    SahgesRequestError
)

client = SahgesAuthClient(client_id="...", client_secret="...")

try:
    response = client.login({
        "credential": "user@example.com",
        "password": "wrong_password"
    })
    
except SahgesAuthenticationError as e:
    if e.status_code == 401:
        print("Identifiants incorrects")
    elif e.status_code == 403:
        print("Compte désactivé ou accès refusé")
    else:
        print(f"Erreur d'authentification: {e}")
        
except SahgesValidationError as e:
    print(f"Données invalides: {e}")
    # Exemple : email mal formaté, mot de passe trop court
    
except SahgesRequestError as e:
    if e.status_code == 429:
        print("Trop de tentatives, réessayez plus tard")
    elif e.status_code >= 500:
        print("Erreur serveur, réessayez plus tard")
    else:
        print(f"Erreur HTTP {e.status_code}: {e}")
        
except Exception as e:
    print(f"Erreur inattendue: {e}")
```

---

**Version actuelle : 0.1.9**

Dernière mise à jour : Janvier 2026
