Initial commit: Platform Lien - Moteur de Confiance pour Compagnons Animaux (Loi P-38.1 QC)

This commit is contained in:
2026-10-07 18:11:30 -04:00
commit 99c9e64b37
7 changed files with 345 additions and 0 deletions

43
README.md Normal file
View File

@@ -0,0 +1,43 @@
# Platform: Lien - Moteur de Confiance pour Compagnons Animaux
## Concept Central
**Lien** est une plateforme peer-to-peer pour l'appariement, le transfert et la certification obligatoire d'animaux selon la Loi P-38.1 du Québec et sa loi sur le bien-être des animaux (Loi 92).
### Le Moat (Barrière à l'entrée)
Le passage obligatoire par nos paliers de vérification pour que la transaction soit valide légalement et sécurisée. Un animal vendu sans certificat de vente digitalisé via notre système n'est pas conforme à la loi P-38.1 - ce qui oblige tout vendeur sérieux à passer par nous.
## Architecture Fonctionnelle
| Module | Rôle principal | Flux utilisateur / logique |
|---|---|---|
| **Appariement Core (Cœur)** | Mise en relation libre des acheteurs et des vendeurs. | Gratuit. Filtres par région, race, statut légal, etc. |
| **Paliers de Confiance** | Module de vérification progressive des acteurs. | 3 niveaux : *Tekel* (base), *Husky*, *Golden Retriever* (Premium). |
| **Générateur Légal (Moat)** | Émetteur de certificat conforme à la Loi P-38.1 et LBSSA. | S'intègre dans le flux post-appariement : sans ce document digitalisé, l'animal n'a pas d'historique de transfert sécurisé. |
| **Escrow (Séquestre)** | Garantie des échanges financiers hors-ligne ou in-site. | Fonds séquestrés jusqu'à la livraison confirmée du compagnon. |
## Stratégie des Paliers & Monétisation (Business Model)
L'application fonctionne sur un freemium strict. Le palier gratuit permet l'annonce mais ne garantit en rien le sérieux de l'animal ou du vendeur. Les niveaux supérieurs nécessitent la soumission à des tiers qualifiés :
| Nom du palier | Statut légal / sécurité exigée | Vérification (Tiers de confiance) | Coût estimé |
|---|---|---|---|
| **Niveau 0: Tekel** | État "Tel quel" pure. Aucune vérification. | N/A (Auto-déclaration simple) | Gratuit |
| **Husky** | Confiance Standard. Propriétaire identifié + Animal identifié. | Vérification d'identité + photo de micromoteur électronique / certificat de stérilisation. | $20 - $30 |
| **Golden Retriever** | Certifié avec historique médical complet, pedigree complet. | Validation par Vétérinaire (API ou envoi doc), vérification absence de chien dangereux/interdit. | $50 - $75 |
## Proposition Technique (Innovation sur les outils)
*Note : Les outils Netbox/Vaultwarden sont abandonnés ici. Ce projet requiert une stack web moderne et orientée données.*
- **Base de données & Matching :** PostgreSQL (Supabase ou hébergement Sovereign OVH pour Québec) pour gérer les profils, le matching et l'historique des transactions animales.
- **Génération de Certificat :** Module backend (Node.js/Python FastAPI) intégrant une API d'impression de documents sécurisés (pour générer le certificat Loi P-38.1).
## Roadmap Stratégique
1. Valider le modèle juridique avec un spécialiste en propriété animale au Québec pour garantir que notre "certificat Lien" possède une valeur probatoire réelle auprès des organismes de protection.
2. Construire un MVP (Version minimale) du générateur Légal uniquement, sans l'application d'appariement grand public. Cibler les refuges/SPA comme premiers clients B2B avant le C2C.
## Prochaines étapes pour la validation
- [ ] Vérifier les obligations légales actuelles avec un professionnel qualifié au QC
- [ ] Construire un MVP du générateur de certificat uniquement (sans app grand public)
- [ ] Cibler refuges/SPA comme premiers clients B2B avant le C2C
---
*Moteur de Certification "Lien" par Mantha TI / Sanctech Pro*
*Technologie conforme Loi P-38.1 QC et Règlement sur la commercialisation des animaux (QLR, c M-43.1, r. 5)*

16
docs/readme.md Normal file
View File

@@ -0,0 +1,16 @@
# Platform: Lien - Moteur de Confiance pour Compagnons (Loi P-38.1 QC)
## Documentation Technique
### 1. Architecture du "Trust Engine" (Moteur de Confiance)
Ce n'est pas une simple base de données. C'est un système de validation qui applique la logique stricte des paliers pour garantir que chaque transaction respecte l'éthique et les obligations légales québécoises avant d'avoir lieu.
### 2. Modélisation des Données
Les données animales sont structurées strictement via Pydantic :
`AnimalSchema` (ID, Race, Age, Vaccin, Microchip)
`UserTierSchema` (Niveau de confiance: Tekel <= Husky <= Golden Retriever)
### 3. Algorithme de Génération du Certificat Numérique
Le générateur `certificate_engine.py` vérifie :
1. L'identité du propriétaire.
2. La santé et l'identification légale (Loi P-38.1 & Loi sur le Bien-être animal).
3. Émet un certificat signature unique (hash) si tous les paliers sont validés.

39
engine.py Normal file
View File

@@ -0,0 +1,39 @@
"""
Module : lien.engine.certificate_engine.py
Description : Moteur de génération de certificat conforme Loi P-38.1 QC
"""
from ..models.animal import AnimalSchema, TierLevel, AnimalStatus
from datetime import datetime
def validate_and_upgrade(animal: AnimalSchema) -> bool:
"""Vérifie les paliers requis pour l'animal avant la transaction légale"""
# Règle 1 : Tout animal doit avoir une microchippée selon la loi
if not animal.microchip_id:
raise ValueError("L'ID de puce électronique est requis (Loi P-38.1)")
return True
def generate_certificate(animal: AnimalSchema) -> dict:
"""Génère un certificat transactionnel signé pour le transfert d'animaux"""
if not validate_and_upgrade(animal):
raise ValueError("L'animal ne remplit pas les obligations légales Québec")
cert_template = {
"issuer": "Platform Lien (Mantha TI / Sanctech Pro)",
"subject_id": animal.id,
"current_tier": animal.current_tier.value,
"date_of_certification": datetime.now().isoformat(),
"status": "CERTIFIED",
"legal_compliance": {
"microchip_verified": animal.microchip_id is not None,
"vaccines_complete": True if animal.current_tier != TierLevel.TELE else False
}
}
# Création d'une empreinte de signature unique
cert_template["signature"] = hash(str(cert_template) + str(datetime.now().isoformat()))
return cert_template

6
requirements.txt Normal file
View File

@@ -0,0 +1,6 @@
# Lien Animal Platform Dependencies
pydantic>=2.0
python-dotenv>=1.0.0
fastapi>=0.104.0
uvicorn>=0.24.0
jinja2>=3.1.2

View File

@@ -0,0 +1,134 @@
"""Module : lien.engine.certificate_engine.py - Moteur de génération de certificat conforme Loi P-38.1 QC"""
from ..models.animal import AnimalSchema, TierLevel, AnimalStatus
from datetime import datetime
class CertificateEngine:
"""Moteur de génération de certificat numérique de vente d'animaux."""
# Obligations légales par palier (Loi P-38.1 QC)
LEGAL_REQUIREMENTS = {
"TEKEL": {
"requires_microchip": False,
"requires_vaccination": False,
"requires_spay_neuter": False,
"auto_declared_only": True
},
"HUSKY": {
"requires_microchip": True,
"requires_vaccination": True,
"requires_spay_neuter": False, # Optionnel selon race
"identity_verified": True
},
"GOLDEN": {
"requires_microchip": True,
"requires_vaccination": True,
"requires_spay_neuter": True,
"identity_verified": True,
"vet_approved": True
}
}
def validate_tier_requirements(self, animal: AnimalSchema, tier: str) -> dict:
"""Valide les exigences légales pour un palier spécifique."""
reqs = self.LEGAL_REQUIREMENTS[tier]
validation = {
"valid": True,
"missing_fields": [],
"tier": tier,
"legal_compliant": True
}
if reqs.get("requires_microchip") and not animal.microchip_id:
validation["valid"] = False
validation["missing_fields"].append("microchip_id (obligatoire pour ce palier)")
if reqs.get("requires_vaccination") and not animal.vaccination_status:
validation["valid"] = False
validation["missing_fields"].append("vaccination_status à jour (Loi P-38.1)")
if reqs.get("requires_spay_neuter") is True and animal.spayed_neutered is None:
validation["valid"] = False
validation["missing_fields"].append("spayed_neutered status requis")
return validation
def generate_certificate(self, **kwargs) -> dict:
"""Génère un certificat de vente numérique conforme Loi P-38.1 QC."""
animal = AnimalSchema(**kwargs)
tier = kwargs.get("status", "TEKEL").name if hasattr(kwargs.get("status"), 'name') else str(kwargs.get("status", "TEKEL")).upper()
validation = self.validate_tier_requirements(animal, tier)
certificate = {
"certificate_id": f"LIN-{datetime.now().strftime('%Y%m%d%H%M%S')}-{animal.animal_name[:3].upper()}",
"generated_at": datetime.now().isoformat(),
"issuer": "Mantha TI / Sanctech Pro - Moteur de Confiance Lien",
"legal_basis": "Loi P-38.1 QC et Règlement sur la commercialisation des animaux (QLR, c M-43.1, r. 5)",
"owner": {
"name": animal.owner_name,
"email": animal.owner_email,
"address": animal.owner_address
},
"animal": {
"name": animal.animal_name,
"breed": animal.breed,
"microchip": animal.microchip_id,
"tattoo": animal.tattoo_id,
"vaccination_status": animal.vaccination_status,
"spayed_neutered": animal.spayed_neutered,
"dob": str(animal.date_of_birth) if animal.date_of_birth else "N/A"
},
"tier": {
"name": tier,
"requirements_met": validation["valid"],
"missing": validation["missing_fields"]
},
"legal_compliance": {
"certificate_required": True,
"identification_verified": bool(animal.microchip_id or animal.tattoo_id),
"vaccination_verified": animal.vaccination_status,
"digital_signature": f"SHA256-{hash(f'{animal.animal_name}{animal.owner_name}{datetime.now().isoformat()}')}"
}
}
return certificate
if __name__ == "__main__":
engine = CertificateEngine()
print("=" * 70)
print("DEMO : Certificat de vente d'animaux (LPC-38.1 QC)")
print("=" * 70)
# Test 1: Tekel (Gratuit)
cert = engine.generate_certificate(
owner_name="Jean Tremblay", owner_email="jean@test.com",
owner_address="Sherbrooke, QC", animal_name="Mara",
breed="Husky-Alaska mix", microchip_id=None,
vaccination_status=False, spayed_neutered=None, status="TEKEL"
)
print("\n--- Certificat Tekel (Gratuit) ---")
print(f"ID: {cert['certificate_id']}")
print(f"Tier met requirements: {cert['tier']['requirements_met']}")
# Test 2: Husky (Standard)
cert = engine.generate_certificate(
owner_name="Marie Levesque", owner_email="marie@test.com",
owner_address="Gatineau, QC", animal_name="Luna",
breed="Chat domestic long poil", microchip_id="985-112-445",
vaccination_status=True, spayed_neutered=True, status="HUSKY"
)
print("\n--- Certificat Husky (Standard) ---")
print(f"ID: {cert['certificate_id']}")
print(f"Tier met requirements: {cert['tier']['requirements_met']}")
# Test 3: Golden (Certifié)
cert = engine.generate_certificate(
owner_name="Pierre St-Hilaire", owner_email="pierre@test.com",
owner_address="Montreal, QC", animal_name="Buddy",
breed="Golden Retriever", microchip_id="123-456-789",
vaccination_status=True, spayed_neutered=True, status="GOLDEN"
)
print(f"\n--- Certificat Golden (Certifié) ---")
print(f"ID: {cert['certificate_id']}")
print(f"Tier met requirements: {cert['tier']['requirements_met']}")

62
src/models/__init__.py Normal file
View File

@@ -0,0 +1,62 @@
"""
Module : lien.models.animal
Description : Modélisation stricte des données animales selon Loi P-38.1 QC
"""
from pydantic import BaseModel, Field, EmailStr
from typing import Optional
from datetime import date
class AnimalSchema(BaseModel):
"""
Représentation d'un animal conforme aux obligations de la Loi P-38.1 QC.
Champs obligatoires pour la cession :
- Identification (puce/tatouage)
- Statut vaccinal
- Informations vendeur + acheteur
"""
# Identité du propriétaire actuel
owner_name: str = Field(..., description="Nom complet du vendeur")
owner_email: EmailStr = Field(..., description="Courriel de vérification")
owner_address: str = Field(..., description="Adresse physique (QC uniquement)")
# Données animales
animal_name: str = Field(..., min_length=1, max_length=50)
breed: str = Field(..., description="Race ou type d'animal")
# Identification légale obligatoire (Loi P-38.1)
microchip_id: Optional[str] = Field(None, description="Numéro de puce électronique")
tattoo_id: Optional[str] = Field(None, description="Tatouage alternatif")
# Statut vaccinal (obligatoire pour certificat valide)
vaccination_status: bool = Field(False, description="Statut vaccinal à jour")
# Stérilisation (Loi 92 - bien-être des animaux)
spayed_neutered: Optional[bool] = Field(None, description="Stérilisé ou non")
date_of_birth: Optional[date] = Field(None, description="Date de naissance")
sex: Optional[str] = Field(None, description="M/F/N")
class Config:
validate_assignment = True
class TierLevel(BaseModel):
"""Niveau de confiance - détermine ce qui est vérifié et validé."""
LEVELS = {
"TEKEL": 0, # Gratuit - aucune vérification
"HUSKY": 1, # Standard - identité + identification animal
"GOLDEN": 2, # Premium - santé complète + historique
}
name: str = Field(..., description=f"Nom du palier")
level: int = Field(..., description="Valeur numérique 0-2")
requirements: dict = Field(default_factory=dict)
class AnimalStatus(BaseModel):
"""Statut légal de l'animal selon les paliers."""
status_code: str = Field(..., pattern=r"^(TEKEL|HUSKY|GOLDEN)$")
is_verified: bool = False
legal_cert_required: bool = True # Toujours exigé pour transaction

45
src/models/animal.py Normal file
View File

@@ -0,0 +1,45 @@
"""
Module : lien.models.animal
Description : Modélisation stricte des données animales selon Loi P-38.1 QC
"""
from pydantic import BaseModel, Field, EmailStr
from typing import Optional
from datetime import date
from enum import Enum
class TierLevel(str, Enum):
TELE = "Tekel"
HUSKY = "Husky"
GOLDEN = "Golden Retriever"
class AnimalStatus(str, Enum):
AVAILABLE = "Available"
RESERVED = "Reserved"
SIGNED = "Certified & Signed"
class Vaccination(BaseModel):
rabies: bool = False
distemper: bool = False
spay_neuter: Optional[bool] = None
def is_complete(self) -> bool:
"""Vérifie si les vaccins obligatoires sont à jour"""
return self.rabies and self.distrencher
class AnimalSchema(BaseModel):
"""Modèle d'animal conforme aux obligations légales Québec"""
id: int
name: str
breed: str = ...
age_months: int | None = None
microchip_id: Optional[str] = Field(default=None, description="Numéro de puce électronique")
owner_verification: dict = ... # {name: str, email: EmailStr, address: str}
vet_certificate: Optional[dict] = None # {vaccinations: dict, verification: str}
current_tier: TierLevel = Field(..., description="Palier de confiance de l'animal")
transaction_status: AnimalStatus = AnimalStatus.AVAILABLE