RGPD & conformité
Sous-traitants, retention, droit à l'oubli, PII en logs, cookies, DPO
HOAIY est sous-traitant pour les données guest (responsable = l'hôtel), responsable pour les données staff. Toutes les infra UE (Hostinger Larnaca, Signoz self-host). Pas de GAFAM US pour les données personnelles sauf Azure OpenAI (traitement AI non-stockage).
Statut RGPD de HOAIY
Pour les données guests
- Responsable de traitement : l'hôtel (utilise Bell pour gérer ses clients)
- Sous-traitant : HOAIY (fournit la plateforme)
- Convention de sous-traitance (DPA) signée entre HOAIY et chaque hôtel à l'onboarding
Pour les données staff (users HOAIY + staff des hôtels)
- Responsable de traitement : HOAIY (c'est son produit, ses comptes)
- Politique de confidentialité publique sur
bell-docs.hoaiy.com/legal/privacy(ouhoaiy.com/legal)
Sous-traitants identifiés
Tous listés dans le DPA signé avec les hôtels. Hébergement tout UE ou équivalent.
| Sous-traitant | Rôle | Localisation | Transfert hors UE ? |
|---|---|---|---|
| Hostinger VPS | Hébergement apps + DB + Redis + Signoz + RustFS | Larnaca, Chypre (UE) | Non |
| Cloudflare R2 | Backups DB + storage (S3-compatible) | Multiple (dépend de la région) | Non (bucket EU) |
| Mews | PMS (sous-traitant de l'hôtel, pas de HOAIY) | Amsterdam, NL | Non |
| Stripe | Paiements | Dublin (siège européen) | Non (branche européenne) |
| Azure OpenAI | LLM concierge | West Europe region (Irlande ou NL) | Non si config correcte |
| Google Workspace SMTP | Envoi d'emails transactionnels | US principalement | ⚠️ Transfert US |
| Reacher | Validation email (self-host) | Chez nous | Non |
| Signoz | Monitoring (self-host) | Chez nous | Non |
Transfert Google Workspace
Gmail utilise des Standard Contractual Clauses (SCCs) + DPF (Data Privacy Framework) de Google. C'est juridiquement OK pour l'instant, mais on envisage de migrer vers un SMTP européen (Brevo, Postmark EU, ScalewayMail) au cas où.
Dans le DPA, mention explicite : "les emails transactionnels transitent par Google Workspace US, sous SCCs + DPF".
Données collectées
Pour les guests
| Type | Finalité | Base légale | Retention |
|---|---|---|---|
| Identité (nom, prénom) | Check-in, adresse de livraison commandes | Exécution du contrat hôtelier | Durée séjour + 3 ans (comptable) |
| Email, téléphone | Communication check-in, notifications | Exécution du contrat | Durée séjour + 3 ans |
| Date de naissance | Vérification majorité (bar, spa) | Obligation légale | Durée séjour + 3 ans |
| Moyen de paiement | Paiement commandes | Exécution du contrat | Stripe gère, on stocke juste paymentIntentId |
| Préférences (allergies, VIP) | Personnalisation du service | Intérêt légitime | Durée séjour |
| Conversations AI + staff | Support + amélioration IA | Intérêt légitime | 2 ans |
| Check-in status + timestamps | Analytics + audit | Intérêt légitime | 3 ans |
| Cookies techniques (session) | Fonctionnement app | Strictement nécessaire | 7 jours (session) |
Pour les staff
| Type | Finalité | Base légale | Retention |
|---|---|---|---|
| Identité, email | Accès au dashboard | Contrat de travail (avec l'hôtel) / Bell account (HOAIY) | Jusqu'à révocation + 1 an |
| Logs d'activité | Audit, support | Intérêt légitime | 1 an |
| Session + IP | Sécurité | Intérêt légitime | 1 an |
Droits des personnes
Implémentation dans Bell :
Droit d'accès
- Guest : bouton "Télécharger mes données" dans la PWA (
/settings/my-data) → génère un JSON avec tout ce qu'on a sur lui (profil, bookings, conversations, messages) - Staff : export équivalent dans
/dashboard/settings/my-data
Technique : procedure Elysia /users/export-my-data qui collecte + JSON + link de téléchargement signé (R2, expires 1h).
Droit de rectification
- Guest : édite son profil dans
/settings/profile(PWA). Pour les champs read-only (email, nom), il doit contacter l'hôtel. - Staff : édite dans
/dashboard/settings/profile
Droit à l'oubli
- Guest : bouton "Supprimer mon compte" → soft delete
user.deletedAt+guest.deletedAt, anonymization des data conservées pour obligations légales (facturation) - Après la retention légale, hard delete physique (cron
@elysiajs/cronqui purge les soft-deleted de + de 3 ans)
Données anonymisées mais conservées (obligation comptable 3 ans) :
- Total des factures, dates, TVA
- Nom hôtel, nom guest → hash
// cron quotidien
async function anonymizeExpired() {
const guests = await db.select().from(guest).where(
and(
isNotNull(guest.deletedAt),
lt(guest.deletedAt, subDays(new Date(), 30)), // 30 jours après soft delete → anonymize
),
);
for (const g of guests) {
await db.update(guest).set({
firstName: "Anonymisé",
lastName: hashShort(g.id),
email: `deleted-${hashShort(g.id)}@anonymized.local`,
phone: null,
notes: null,
}).where(eq(guest.id, g.id));
}
}
async function hardDeleteExpired() {
await db.delete(guest).where(
and(
isNotNull(guest.deletedAt),
lt(guest.deletedAt, subYears(new Date(), 3)), // 3 ans → hard delete
),
);
}Droit d'opposition / portabilité
- Opposition : opt-out des emails marketing via lien dans chaque email +
/settings/notifications - Portabilité : JSON export (voir droit d'accès)
Délai de réponse
1 mois à partir de la demande (allongeable de 2 mois si complexe). Trackée dans un ticket interne + alerting Signoz si un ticket "rgpd" dépasse 25 jours.
Logs sans PII
Voir Monitoring.
- Jamais d'email complet dans les logs — toujours hashé (
hashEmail(email)) - Jamais de téléphone, adresse, numéro de carte
- Tokens Better Auth jamais loggés, même tronqués
- Linter custom
no-pii-in-logs(à écrire) : détectelogger.*({ email: ... })au commit
Cookies
Catégories
| Catégorie | Cookie | Base légale | Consentement requis |
|---|---|---|---|
| Strictement nécessaire | better-auth.session_token | Exécution du contrat | Non |
| Préférences | (aucun pour l'instant) | — | Oui si ajoutés |
| Analytics | Aucun (on utilise Signoz côté serveur, pas de pixel tracking) | — | Oui si ajoutés |
| Marketing | Aucun | — | Oui si ajoutés |
Bandeau cookies
Au MVP : pas de bandeau requis puisqu'on n'a que des cookies strictement nécessaires. Si on ajoute de l'analytics (Plausible self-host envisagé, sans PII), on pourrait toujours éviter le bandeau car Plausible ne track pas individuellement.
Si un jour on veut du marketing/retargeting : bandeau obligatoire avec consentement granulaire (pas juste Accept All).
Chiffrement
- En transit : TLS 1.3 partout (Let's Encrypt via Traefik)
- Au repos :
- Postgres : chiffrement disque VPS (Hostinger fournit)
- Backups R2 : server-side encryption (R2 chiffre par défaut)
integration.credentialschiffrés en AES-256 au niveau app avecENCRYPTION_KEY(32 bytes, env var, différent par env)
Rotation ENCRYPTION_KEY
Procédure rare (tous les 2 ans ou sur incident) :
- Générer nouvelle key
- Décrypter tous les
integration.credentialsavec ancienne, ré-encrypter avec nouvelle - Deployer nouveau key
- Runbook détaillé dans
operations/runbooks/rotate-encryption-key.mdx(à écrire)
Accès aux données
Principe du moindre privilège :
| Donnée | Qui y accède |
|---|---|
| Guest profile d'un hôtel | Staff+ de cet hôtel, admin HOAIY |
| Guest password | Personne (hashé Better Auth, impossible à lire) |
| Guest payment | Stripe (on stocke juste paymentIntentId + status) |
| Logs Signoz | Admin HOAIY |
| Backups R2 | Admin HOAIY (accès IAM limité) |
| Credentials Mews (chiffrés) | Admin HOAIY (via /admin/system/integrations) |
| AI conversations | Staff+ de l'hôtel, admin HOAIY |
DPO (Data Protection Officer)
Nommé par HOAIY. Email dpo@hoaiy.com. Contact listé dans la politique de confidentialité.
Responsabilités :
- Tenir le registre des traitements
- Recevoir les demandes de droits des personnes
- Auditer annuellement l'infra + les sous-traitants
- Être le contact de la CNIL en cas de contrôle ou breach
Breach notification
En cas de fuite de données :
- Détection (Signoz alerte ou signalement externe)
- Confinement immédiat (isoler le service compromis)
- Évaluer l'impact (combien de personnes, quelles données)
- Si risque élevé → notification CNIL sous 72h + personnes concernées
- Runbook incident dans
operations/runbooks/data-breach.mdx(à écrire)
Audit log
Toute action sensible (édition d'un guest, suppression, changement de role staff, accès aux credentials integration) est loggée dans activity_log avec :
- Qui :
userId - Quoi :
activity_type - Quand : timestamp
- Sur quoi :
entity_type+entity_id - Depuis où :
ip_address,user_agent
Visible dans /admin/events (admin HOAIY uniquement).
Consentements marketing
Les guests ont une checkbox explicite sur la page check-in paiement :
☐ Je souhaite recevoir des offres exclusives et promotions par email.
Stocké dans guest.marketing_consent. Si non coché → pas d'email commercial. Si décoché plus tard → on stoppe.
Minimisation
On collecte le strict nécessaire :
- Pas de date de naissance si pas de service âge-restricted
- Pas d'adresse si pas de service delivery hors hôtel
- Pas de photo de pièce d'identité (scan passeport) — sauf si obligation légale (fiche de police France) et là c'est l'hôtel qui gère via son PMS, pas Bell