Design: Control Plane¶
Brand: Papillon HR Suite (tenant-facing) + Admin Console (ALTARYS operators)¶
Date: 26/02/2026¶
Version: 1.0¶
Author: DESIGNER (Claude — Senior UX/UI Designer)¶
PRD Source: docs/prd/control-plane-prd.md v1.0¶
For the DEVELOPER: This document is your single source of truth for all Control Plane screens. It references design tokens from
docs/design/host-shell-design.md §2— reuse them, never redefine. The Admin Console is a separate React application (seedocs/_kb/seperate_admin-app_reasons.md). If something is ambiguous, the design is wrong — flag it.
Table of Contents¶
- Scope & Screens Index
- User Flow Diagrams
- Tenant Self-Onboarding (Channel A)
- Email Verification & Post-Verification Routing
- Payment Flow
- Company Settings
- Organization & Master Data
- Employee Management (Baseline)
- User Management & Invitations
- Module Gating & Upsell
- Billing & Subscription Management
- Audit Trail Viewer
- Multi-Tenant Switcher
- Tenant Status Banners
- Admin Console (Separate App)
- Offline Behavior Specifications
- Responsive Behavior Summary
- French Micro-copy Document
- New Component Specifications
- Brand Compliance Checklist
1. Scope & Screens Index¶
The Control Plane touches every surface of the application but most of its UI is administrative setup — screens visited once or occasionally, not daily. The design prioritizes clarity over density.
Screen Map — Papillon HR Suite (Tenant-Facing)¶
| Screen | Location in Nav | Frequency | Offline? | Section |
|---|---|---|---|---|
| Self-Registration (Channel A) | Public — papillon.ci/inscription |
One-time | No | §3 |
| Email Verification | Public — email link | One-time | No | §4 |
| Module Selection | Registration flow step 2 | One-time | No | §3.3 |
| Payment | Registration flow step 3 | One-time (then monthly) | No | §5 |
| Company Settings | Admin → Paramètres → Entreprise | Rare | Partial (read) | §6 |
| Org Structure | Admin → Paramètres → Structure | Monthly | Yes (read) | §7 |
| Position Catalog | Admin → Paramètres → Postes | Monthly | Yes (read) | §7.4 |
| Employee List | RH → Employés | Daily | Yes (full) | §8 |
| Employee Form (Create/Edit) | RH → Employés → Nouveau | Weekly | Yes (create) | §8.3 |
| User Management | Admin → Utilisateurs | Monthly | No | §9 |
| Invite User | Admin → Utilisateurs → Inviter | Monthly | No | §9 |
| Module Catalog (Upsell) | Nav → locked module click | Occasional | No | §10 |
| Subscription Management | Admin → Abonnement | Monthly | No | §11 |
| Invoice History | Admin → Abonnement → Factures | Monthly | No | §11 |
| Audit Trail | Admin → Audit | Rare | No | §12 |
| Tenant Switcher | Header → "Mes entreprises" | Per session | No | §13 |
Screen Map — Admin Console (ALTARYS Operators)¶
| Screen | Frequency | Section |
|---|---|---|
| Tenant List (Dashboard) | Daily | §15.2 |
| Tenant Detail | Daily | §15.3 |
| Pending Payments | Daily | §15.4 |
| Module Override | Weekly | §15.5 |
| Country Config Editor | Rare | §15.6 |
| Platform Metrics | Weekly | §15.7 |
2. User Flow Diagrams¶
2.1 Tenant Self-Onboarding (Channel A)¶
flowchart TD
A[Visiteur arrive sur papillon.ci] --> B[Clique 'Inscription']
B --> C[Formulaire d'inscription]
C --> D{Validation côté client}
D -->|Erreurs| C
D -->|OK| E{hCaptcha}
E -->|Échec| C
E -->|OK| F{Vérification doublons}
F -->|Email/Tél existant| G[Erreur: compte existe déjà]
F -->|Nom similaire| H[Flag ops + continuer]
F -->|OK| I[Enregistrement tenant<br>Status: PENDING_VERIFICATION]
H --> I
I --> J[Email de vérification envoyé]
J --> K{L'utilisateur clique le lien}
K -->|Lien expiré| L[Page: lien expiré<br>+ bouton renvoyer]
L --> J
K -->|Lien valide| M{A choisi l'essai gratuit ?}
M -->|Oui| N[Pipeline de provisionnement]
M -->|Non| O[Page: Sélection modules<br>+ choix de paiement]
N --> P[Status: TRIAL<br>Redirect → Dashboard]
O --> Q{Méthode de paiement}
Q -->|Mobile Money| R[Widget paiement]
Q -->|Virement bancaire| S[Status: ACTIVE_PAYMENT_PENDING<br>Instructions virement affichées]
R -->|Succès| T{RCCM + NIF fournis ?}
R -->|Échec| U[Status: PAYMENT_REQUIRED<br>Modules en lecture seule]
T -->|Oui| V[Status: ACTIVE]
T -->|Non| W[Status: ACTIVE_INCOMPLETE<br>Bandeau persistant]
V --> X[Redirect → Dashboard 🎉]
W --> X
U --> Y[Redirect → Dashboard<br>+ bandeau paiement]
S --> Z[Redirect → Dashboard<br>+ bandeau virement]
style P fill:#DCFCE7
style V fill:#DCFCE7
style W fill:#FEF9C3
style U fill:#FEE2E2
style X fill:#DCFCE7
2.2 Channel B — CRM Salesperson Onboarding¶
flowchart TD
A[Commercial dans CRM:<br>'Convertir en client'] --> B[Tenant créé<br>Status: PENDING]
B --> C[Email #1: lien création<br>mot de passe]
B --> D[Email #2: lien paiement<br>+ résumé modules]
C --> E{Admin crée son mot de passe}
E -->|Lien expiré| F[Contacter commercial]
E -->|Mot de passe créé| G{Paiement effectué ?}
G -->|Mobile Money OK| H[Status: ACTIVE]
G -->|Virement choisi| I[Status: ACTIVE_PAYMENT_PENDING]
G -->|Pas encore| J[Status: PAYMENT_REQUIRED]
D --> K[Admin clique opt-out ?]
K -->|Oui| L[Tenant supprimé<br>Page de confirmation]
style H fill:#DCFCE7
style I fill:#FEF9C3
style J fill:#FEE2E2
style L fill:#E8E0D4
2.3 Tenant Lifecycle State Machine¶
stateDiagram-v2
[*] --> PENDING_VERIFICATION : Channel A
[*] --> PENDING : Channel B (CRM)
PENDING_VERIFICATION --> TRIAL : Email vérifié + essai
PENDING_VERIFICATION --> PAYMENT_REQUIRED : Email vérifié, pas d'essai
PENDING --> PAYMENT_REQUIRED : Mot de passe créé
PENDING --> ACTIVE_PAYMENT_PENDING : MdP + virement
PENDING --> ACTIVE : MdP + paiement API
TRIAL --> ACTIVE : Paiement reçu
TRIAL --> ACTIVE_INCOMPLETE : Paiement reçu, info légale manquante
TRIAL --> ACTIVE_PAYMENT_PENDING : Virement choisi
TRIAL --> SUSPENDED : 14 jours expirés
PAYMENT_REQUIRED --> TRIAL : Essai unique demandé
PAYMENT_REQUIRED --> ACTIVE : Paiement reçu
PAYMENT_REQUIRED --> ACTIVE_INCOMPLETE : Paiement, info manquante
PAYMENT_REQUIRED --> ACTIVE_PAYMENT_PENDING : Virement choisi
PAYMENT_REQUIRED --> SUSPENDED : 14 jours expirés
ACTIVE_PAYMENT_PENDING --> ACTIVE : Paiement confirmé
ACTIVE_PAYMENT_PENDING --> ACTIVE_INCOMPLETE : Confirmé, info manquante
ACTIVE_PAYMENT_PENDING --> SUSPENDED : 10 jours expirés
ACTIVE_INCOMPLETE --> ACTIVE : Info légale complétée
ACTIVE --> SUSPENDED : Abonnement expiré + grâce
ACTIVE --> SUSPENDED : Suspension manuelle admin
SUSPENDED --> ACTIVE : Paiement / réactivation
SUSPENDED --> DELETED : 30 jours sans action
2.4 Employee Creation (Online + Offline)¶
flowchart TD
A[Admin/RH clique<br>'Nouvel employé'] --> B[Formulaire employé]
B --> C{Connectivité ?}
C -->|En ligne| D[Validation côté client]
D -->|Erreurs| B
D -->|OK| E[UUID v7 généré côté client]
E --> F[POST /api/v1/employees]
F --> G{Réponse serveur}
G -->|201 Created| H[Matricule assigné par serveur<br>Toast: 'Employé créé ✓']
G -->|409 Conflit| I[Doublon email/tél<br>Afficher résolution]
G -->|Erreur réseau| J[Sauvegarder IndexedDB<br>File de sync]
C -->|Hors ligne| K[Validation côté client]
K -->|Erreurs| B
K -->|OK| L[UUID v7 généré côté client]
L --> M[Sauvegardé IndexedDB<br>Matricule: 'Numéro en attente']
M --> N[Toast: 'Employé enregistré<br>hors ligne ●']
N --> O{Connectivité restaurée}
O --> F
style H fill:#DCFCE7
style N fill:#FEF9C3
style I fill:#FEE2E2
style J fill:#FEF9C3
3. Tenant Self-Onboarding (Channel A)¶
3.1 Registration Page — Step 1: Company Information¶
URL: papillon.ci/inscription
Public: No authentication required
No offline support — onboarding requires connectivity
Layout — Mobile (360px)¶
┌──────────────────────────────────────┐
│ (warm bg #FFFDF7) │
│ │
│ 🦋 │
│ Créez votre compte │
│ Papillon en 5 minutes │
│ │
│ ┌──────────────────────────────┐ │
│ │ │ │
│ │ Nom de l'entreprise * │ │
│ │ ┌──────────────────────┐ │ │
│ │ │ │ │ │
│ │ └──────────────────────┘ │ │
│ │ │ │
│ │ Pays │ │
│ │ ┌──────────────────────┐ │ │
│ │ │ 🇨🇮 Côte d'Ivoire ▾ │ │ │ ← Pre-selected, disabled for MVP
│ │ └──────────────────────┘ │ │
│ │ │ │
│ │ Nombre de salariés * │ │
│ │ ┌──────────────────────┐ │ │
│ │ │ ▾ │ │ │ ← Dropdown with ranges
│ │ └──────────────────────┘ │ │
│ │ │ │
│ │ Votre nom complet * │ │
│ │ ┌──────────────────────┐ │ │
│ │ │ │ │ │
│ │ └──────────────────────┘ │ │
│ │ │ │
│ │ Adresse e-mail * │ │
│ │ ┌──────────────────────┐ │ │
│ │ │ │ │ │
│ │ └──────────────────────┘ │ │
│ │ │ │
│ │ Numéro de téléphone * │ │
│ │ ┌─────┬────────────────┐ │ │
│ │ │+225 │ │ │ │ ← Country code pre-filled
│ │ └─────┴────────────────┘ │ │
│ │ │ │
│ │ RCCM (optionnel) │ │
│ │ ┌──────────────────────┐ │ │
│ │ │ │ │ │
│ │ └──────────────────────┘ │ │
│ │ ℹ Vous pourrez le fournir │ │
│ │ plus tard │ │
│ │ │ │
│ │ ☐ Démarrer un essai │ │
│ │ gratuit de 14 jours │ │ ← Checkbox, unchecked by default
│ │ │ │
│ │ ┌──────────────────────┐ │ │
│ │ │ Continuer → │ │ │ ← Primary button → Step 2
│ │ └──────────────────────┘ │ │
│ │ │ │
│ │ Déjà inscrit ? │ │
│ │ Se connecter │ │ ← Link to login
│ │ │ │
│ └──────────────────────────────┘ │
│ │
│ © 2026 ALTARYS ENTERPRISE │
└──────────────────────────────────────┘
Layout — Desktop (1024px+)¶
Split layout like the login screen (host-shell-design.md §4.1):
- Left panel (50%): Deep teal #0D6B6E with warm geometric SVG illustration, tagline "Simplifiez la gestion de vos RH", trust badges ("Conforme OHADA", "Données sécurisées", "Support réactif")
- Right panel (50%): White card surface with the form fields
Field Specifications¶
| Field | Type | Required | Validation | Max Length |
|---|---|---|---|---|
| company_name | text input | Yes | min 2 chars | 200 |
| country_code | select (disabled MVP) | Yes | Pre-set: "CI" | — |
| employee_count | select (dropdown) | Yes | Ranges: 2-12, 13-29, 30-49, 50-99, 100-199, 200-350 | — |
| admin_full_name | text input | Yes | min 2 chars | 200 |
| admin_email | email input | Yes | email format, unique | 254 |
| admin_phone | phone input with prefix | Yes | CI format: 10 digits, unique | 10 digits |
| rccm | text input | No | — | 50 |
| free_trial | checkbox | No | — | — |
Employee Count Dropdown Options: - "2 – 12 salariés" - "13 – 29 salariés" - "30 – 49 salariés" - "50 – 99 salariés" - "100 – 199 salariés" - "200 – 350 salariés"
Why ranges not exact number: Ranges map directly to pricing segments (S1–S6). Users don't need to count exactly — they know their rough size. This avoids analysis paralysis ("Is it 47 or 48?") and prevents gaming (entering a lower number to get a cheaper plan — the system snapshots actual active employees at billing time).
Interaction Specification¶
| State | Behavior |
|---|---|
| Empty | All fields empty except country (pre-filled). Button enabled. |
| Typing | Real-time validation: email format check after blur, phone format check as user types (auto-format: XX XX XX XX XX) |
| Validation error | Red border on field + error message below field in --color-error. Field shakes once (150ms). |
| Duplicate email/phone | After submit: "Un compte existe déjà avec ces informations. Essayez de vous connecter." with link to login. |
| hCaptcha | Appears after "Continuer" click, before submission. Invisible reCaptcha first; fallback to challenge if suspicious. |
| Submitting | Button: spinner + "Envoi en cours…" — all fields disabled |
| Server error | Toast: "Une erreur est survenue. Veuillez réessayer." + fields remain filled (never clear on error) |
| Rate limited | Toast: "Trop de tentatives. Veuillez réessayer dans quelques minutes." |
3.2 Registration Page — Step 2: Module Selection¶
After Step 1 validation, user advances to module selection. This is the first time the user sees the product catalog. It must be aspirational — show the breadth of what Papillon offers, make the selection exciting (not administrative).
Layout — Mobile (360px)¶
┌──────────────────────────────────────┐
│ ← Retour Inscription (2/3) │
├──────────────────────────────────────┤
│ │
│ Choisissez vos modules │
│ Sélectionnez au moins 1 module. │
│ Vous pourrez en ajouter plus tard. │
│ │
│ ── Disponible maintenant ──────── │
│ │
│ ┌──────────────────────────────┐ │
│ │ ☐ 📅 Gestion des Absences │ │
│ │ Congés, demandes, │ │
│ │ approbations │ │
│ │ 12 000 FCFA │ │ ← Price per segment
│ └──────────────────────────────┘ │
│ │
│ ┌──────────────────────────────┐ │
│ │ ☐ 📱 Contrôle Présence │ │
│ │ Pointage QR Code │ │
│ │ 5 000 FCFA │ │
│ └──────────────────────────────┘ │
│ │
│ ── Bientôt disponible ────────── │
│ │
│ ┌──────────────────────────────┐ │
│ │ 🔒 💳 Paie │ │ ← Locked, greyed
│ │ Juin 2026 │ │
│ └──────────────────────────────┘ │
│ ┌──────────────────────────────┐ │
│ │ 🔒 🧾 Notes de Frais │ │
│ │ Avril 2026 │ │
│ └──────────────────────────────┘ │
│ ... │
│ │
│ ── Votre sélection ───────────── │ ← Sticky bottom summary
│ ┌──────────────────────────────┐ │
│ │ 2 modules · 17 000 FCFA/m │ │
│ │ Pack Contrôle appliqué │ │ ← Auto-detected pack
│ │ → 15 000 FCFA/mois (-12%) │ │
│ │ │ │
│ │ ┌──────────────────────┐ │ │
│ │ │ Continuer → │ │ │
│ │ └──────────────────────┘ │ │
│ └──────────────────────────────┘ │
└──────────────────────────────────────┘
Module Card Component¶
Each module card contains:
- Checkbox (left): for selection. Touch target 48×48px.
- Icon (center-left): Module icon in --color-primary (available) or --color-text-tertiary (locked)
- Title: Module name (--font-h4)
- Subtitle: One-line description (--font-small, --color-text-secondary)
- Price: Monthly price for the user's segment (--font-body-medium, --color-primary)
- Lock badge (for unavailable modules): "Bientôt · [date]"
Card states:
- Available, unselected: White background, standard border
- Available, selected: --color-primary-light background, --color-primary border, amber checkmark
- Locked: 60% opacity, no checkbox, lock icon replaces checkbox, "Bientôt" badge
Pack Auto-Detection¶
When the user's selection matches a pack combination (as defined in docs/specs/tarifs_papillon_hr_suite.md):
- The sticky summary shows: "Pack [name] détecté · -XX%" with crossed-out original price
- Animation: price slides from original to discounted with a brief sparkle
- Pack detection is instant (client-side calculation)
3.3 Registration Page — Step 3: Payment Choice¶
Shown only if user did NOT select free trial in Step 1. If free trial was selected, Steps 1 + 2 → email verification → TRIAL → Dashboard.
Layout — Mobile (360px)¶
┌──────────────────────────────────────┐
│ ← Retour Inscription (3/3) │
├──────────────────────────────────────┤
│ │
│ Comment souhaitez-vous payer ? │
│ │
│ ── Résumé de votre abonnement ── │
│ ┌──────────────────────────────┐ │
│ │ Absences + Présence QR │ │
│ │ Pack Contrôle │ │
│ │ 15 000 FCFA / mois │ │
│ └──────────────────────────────┘ │
│ │
│ ┌──────────────────────────────┐ │
│ │ 📱 Paiement Mobile Money │ │ ← Primary option
│ │ Orange Money, Wave, │ │
│ │ MTN Money │ │
│ │ │ │
│ │ Paiement instantané. │ │
│ │ Accès immédiat. │ │
│ │ │ │
│ │ ┌──────────────────────┐ │ │
│ │ │ Payer 15 000 FCFA │ │ │ ← Primary button
│ │ └──────────────────────┘ │ │
│ └──────────────────────────────┘ │
│ │
│ ┌──────────────────────────────┐ │
│ │ 🏦 Virement bancaire │ │ ← Secondary option
│ │ │ │
│ │ Délai de traitement : │ │
│ │ 10 jours maximum. │ │
│ │ Accès complet pendant │ │
│ │ cette période. │ │
│ │ │ │
│ │ ┌──────────────────────┐ │ │
│ │ │ Choisir le virement │ │ │ ← Secondary button (outlined)
│ │ └──────────────────────┘ │ │
│ └──────────────────────────────┘ │
│ │
│ ┌──────────────────────────────┐ │
│ │ 🎁 Essai gratuit 14 jours │ │ ← If not yet used
│ │ Testez avant de payer. │ │
│ │ Démarrer l'essai → │ │ ← Text link
│ └──────────────────────────────┘ │
│ │
└──────────────────────────────────────┘
Payment Method Interaction¶
Mobile Money selected: 1. Button changes to spinner + "Redirection…" 2. Payment provider widget opens (in-app WebView or redirect) 3. On success → webhook confirms → tenant provisioned → redirect to Dashboard 4. On failure → return to payment page with toast: "Le paiement n'a pas abouti. Réessayez ou choisissez un autre mode." 5. On abandon (user closes widget) → return to payment page, no error
Virement bancaire selected: 1. Show bank details screen: - Bank name, IBAN, account holder - Reference to include in transfer (tenant ID short code) - "Prenez une capture d'écran de ces informations" - Copy-to-clipboard buttons for IBAN and reference 2. Tenant provisioned with status ACTIVE_PAYMENT_PENDING 3. Redirect to Dashboard with banner (see §14)
Essai gratuit selected: 1. Confirm modal: "Votre essai de 14 jours commence maintenant. Tous les modules sélectionnés seront actifs." 2. Tenant provisioned with status TRIAL 3. Redirect to Dashboard with welcome celebration 🎉
4. Email Verification & Post-Verification Routing¶
4.1 Verification Email¶
Subject: "Confirmez votre inscription Papillon" From: [email protected] Body (French, Papillon-branded):
Bonjour [admin_full_name],
Bienvenue sur Papillon ! 🦋
Cliquez sur le bouton ci-dessous pour confirmer votre adresse e-mail et finaliser votre inscription.
[Confirmer mon adresse e-mail] ← Primary CTA button
Ce lien expire dans 24 heures.
Si vous n'avez pas demandé cette inscription, ignorez cet e-mail.
L'équipe Papillon ALTARYS ENTERPRISE
4.2 Verification Landing Page¶
URL: papillon.ci/verification?token=xxx
| State | Screen |
|---|---|
| Valid token | "✓ Adresse e-mail confirmée !" → auto-redirect after 2s to next step (Trial setup or Payment choice) |
| Expired token | "Ce lien a expiré." + "Renvoyer un e-mail de vérification" button (max 3 resends / 24h) |
| Invalid token | "Ce lien n'est pas valide." + "Retour à l'inscription" link |
| Already verified | "Votre adresse est déjà confirmée." + "Se connecter" link |
4.3 Post-Verification Routing Logic¶
IF free_trial = true AND trial_not_used:
→ Provision tenant (TRIAL status)
→ Redirect to password creation
→ Redirect to Dashboard
IF free_trial = false:
→ Redirect to Module Selection (if not already done)
→ Redirect to Payment Choice
→ Provision tenant based on payment outcome
5. Payment Flow¶
5.1 Mobile Money Payment Widget¶
The payment flow uses the PaymentProvider adapter pattern. The UI renders a provider-agnostic experience:
- Pre-payment screen: Summary card (modules, price, pack if applicable)
- Provider selection (if multiple providers available):
- "Orange Money" with orange logo
- "Wave" with wave logo
- "MTN Money" with MTN logo
- Each shows phone number input pre-filled with admin phone
- Provider redirect/widget: Handled by provider SDK
- Confirmation: Webhook-based — user sees "Paiement en cours de traitement…" with a pulsing indicator
- Success: Green checkmark + "Paiement confirmé ! Bienvenue sur Papillon."
5.2 Payment States¶
| State | UI | Timing |
|---|---|---|
| Initiating | Button spinner + "Redirection vers [provider]…" | 1-3s |
| Processing | Full-screen loading: "Veuillez confirmer le paiement sur votre téléphone" | 5-60s |
| Success | Green checkmark + success message + auto-redirect to Dashboard (3s) | Instant |
| Failed | Toast: "Le paiement a échoué. Veuillez réessayer." + return to payment choice | Instant |
| Timeout | After 90s: "Le paiement prend plus de temps que prévu. Nous vous notifierons par e-mail dès confirmation." + redirect to Dashboard (PAYMENT_REQUIRED) | 90s |
6. Company Settings¶
Location in nav: Admin → Paramètres → Entreprise Access: DG and RH Manager roles Offline: Read-only (view settings). Write requires connectivity.
6.1 Company Information Tab¶
Layout — Mobile (360px)¶
┌──────────────────────────────────────┐
│ ← Paramètres Entreprise │
├──────────────────────────────────────┤
│ │
│ ┌──────────────────────────────┐ │
│ │ [Logo placeholder] │ │
│ │ 📷 Modifier le logo │ │ ← Tap to upload
│ └──────────────────────────────┘ │
│ │
│ Nom de l'entreprise │
│ ┌──────────────────────────────┐ │
│ │ Acme SARL │ │
│ └──────────────────────────────┘ │
│ │
│ Forme juridique │
│ ┌──────────────────────────────┐ │
│ │ SARL ▾ │ │
│ └──────────────────────────────┘ │
│ │
│ RCCM │
│ ┌──────────────────────────────┐ │
│ │ CI-ABJ-2024-B-12345 │ │
│ └──────────────────────────────┘ │
│ │
│ NIF │
│ ┌──────────────────────────────┐ │
│ │ │ │ ← Empty if ACTIVE_INCOMPLETE
│ └──────────────────────────────┘ │
│ ⚠ Requis pour la facturation │
│ normalisée (FNE) │
│ │
│ Adresse │
│ ┌──────────────────────────────┐ │
│ │ Abidjan, Cocody, Rue X │ │
│ └──────────────────────────────┘ │
│ │
│ Secteur d'activité │
│ ┌──────────────────────────────┐ │
│ │ Commerce ▾ │ │
│ └──────────────────────────────┘ │
│ │
│ ── Configuration ──────────────── │
│ │
│ Année fiscale (début) │
│ ┌──────────────────────────────┐ │
│ │ Janvier ▾ │ │
│ └──────────────────────────────┘ │
│ │
│ Jours ouvrables / semaine │
│ ┌──────────────────────────────┐ │
│ │ 5 ▾ │ │
│ └──────────────────────────────┘ │
│ │
│ Heures / jour │
│ ┌──────────────────────────────┐ │
│ │ 8 ▾ │ │
│ └──────────────────────────────┘ │
│ │
│ Classe de risque AT/MP │
│ ┌──────────────────────────────┐ │
│ │ Classe 1 (2%) ▾ │ │
│ └──────────────────────────────┘ │
│ ℹ Utilisé pour le calcul │
│ des cotisations CNPS │
│ │
│ ── Format Matricule Employé ───── │
│ │
│ Préfixe │
│ ┌──────────────────────────────┐ │
│ │ EMP │ │
│ └──────────────────────────────┘ │
│ │
│ Nombre de chiffres │
│ ┌──────────────────────────────┐ │
│ │ 4 ▾ │ │
│ └──────────────────────────────┘ │
│ Aperçu : EMP-2026-03-001 │
│ │
│ ── Approbateur par défaut ─────── │
│ │
│ ┌──────────────────────────────┐ │
│ │ 👤 Éric Blonvia (DG) ▾ │ │
│ └──────────────────────────────┘ │
│ ℹ Reçoit les demandes si un │
│ employé n'a pas de manager │
│ │
└──────────────────────────────────────┘
Auto-Save Behavior¶
- Every field saves automatically on blur (no "Save" button)
- On save: brief green checkmark appears next to the field label (150ms fade in, holds 2s, 300ms fade out)
- On error: red border + error message below field
- On offline: orange dot appears next to field + "Modification enregistrée hors ligne" toast
Desktop Layout (1024px+)¶
Two-column form layout: - Left column: Company identity fields (name, legal form, RCCM, NIF, address, sector) - Right column: Configuration fields (fiscal year, working days, hours, AT/MP class, matricule format, default approver)
7. Organization & Master Data¶
7.1 Org Structure Tree¶
Location in nav: Admin → Paramètres → Structure de l'entreprise Access: DG and RH Manager roles Offline: Read (browse tree). Write (add/edit units) queues for sync.
Layout — Mobile (360px)¶
┌──────────────────────────────────────┐
│ ← Paramètres Structure │
├──────────────────────────────────────┤
│ │
│ 🏢 Acme SARL │ ← Root Entity (non-editable)
│ │ │
│ ├── 📍 Siège Abidjan │ ← Site (optional level)
│ │ ├── 🏛 Direction Générale │
│ │ ├── 🏛 Ressources Humaines │
│ │ ├── 🏛 Comptabilité │
│ │ ├── 🏛 Commercial │
│ │ ├── 🏛 Production │
│ │ └── 🏛 Informatique │
│ │ │
│ └── 📍 Usine San Pedro │ ← Second site
│ └── 🏛 Production SP │
│ │
│ ┌──────────────────────────────┐ │
│ │ + Ajouter une unité │ │ ← FAB or button at bottom
│ └──────────────────────────────┘ │
│ │
└──────────────────────────────────────┘
Tree Interaction¶
| Action | Mobile | Desktop |
|---|---|---|
| Expand/collapse | Tap node → toggles children | Click chevron → toggles |
| View details | Tap node name → bottom sheet with name, type, status, employee count | Click → right panel slide-in |
| Add child | Long-press parent → "Ajouter sous [name]" action | Click "+" icon that appears on hover |
| Edit | In detail bottom sheet: edit name, deactivate | In detail panel: inline edit |
| Deactivate | In detail bottom sheet: "Désactiver" → undo toast | In detail panel: toggle switch |
| Reorder | Not supported MVP | Not supported MVP |
Add Unit Flow¶
When "Ajouter une unité" is tapped:
┌──────────────────────────────────────┐
│ │
│ ── Nouvelle unité ────────────── │ ← Bottom sheet (mobile)
│ │
│ Type * │
│ ┌──────────────────────────────┐ │
│ │ ○ Site / Établissement │ │
│ │ ○ Département / Service │ │
│ └──────────────────────────────┘ │
│ │
│ Nom * │
│ ┌──────────────────────────────┐ │
│ │ │ │
│ └──────────────────────────────┘ │
│ │
│ Rattachée à * │
│ ┌──────────────────────────────┐ │
│ │ 🏢 Acme SARL (Entité) ▾ │ │ ← Parent selector
│ └──────────────────────────────┘ │
│ │
│ ┌──────────────────────────────┐ │
│ │ Ajouter │ │
│ └──────────────────────────────┘ │
│ │
└──────────────────────────────────────┘
Validation rules: - Site's parent must be the Entity - Department's parent can be Entity or a Site - Name must be unique within the same parent
7.2 Org Structure — Desktop (1024px+)¶
Master-detail layout: - Left panel (40%): Interactive tree with expand/collapse chevrons, search filter at top - Right panel (60%): Selected unit details — name (editable), type badge, status toggle, employee count, "Ajouter un sous-département" button
7.3 Category Management¶
Location: Admin → Paramètres → Catégories de salariés Simple list view:
┌──────────────────────────────────────┐
│ Catégories de salariés │
│ │
│ ℹ Les catégories système ne │
│ peuvent pas être supprimées. │
│ │
│ ┌──────────────────────────────┐ │
│ │ CAD · Cadre 🔒 │ │ ← System (is_system = true)
│ ├──────────────────────────────┤ │
│ │ AM · Agent de maîtrise 🔒 │ │
│ ├──────────────────────────────┤ │
│ │ EMP · Employé 🔒 │ │
│ ├──────────────────────────────┤ │
│ │ OUV · Ouvrier 🔒 │ │
│ ├──────────────────────────────┤ │
│ │ STG · Stagiaire ✏️ │ │ ← Custom (is_system = false)
│ └──────────────────────────────┘ │
│ │
│ + Ajouter une catégorie │
│ │
└──────────────────────────────────────┘
7.4 Position Catalog¶
Location: Admin → Paramètres → Postes Searchable list with category association:
┌──────────────────────────────────────┐
│ Référentiel des postes │
│ │
│ 🔍 Rechercher un poste… │
│ │
│ ┌──────────────────────────────┐ │
│ │ Directeur Général │ │
│ │ Catégorie: Cadre · DG │ │
│ ├──────────────────────────────┤ │
│ │ Responsable RH │ │
│ │ Catégorie: Cadre · RH │ │
│ ├──────────────────────────────┤ │
│ │ Comptable │ │
│ │ Catégorie: AM · Comptabilité│ │
│ ├──────────────────────────────┤ │
│ │ Chauffeur ✨ │ │ ← Custom position (is_custom)
│ │ Catégorie: Ouvrier │ │
│ └──────────────────────────────┘ │
│ │
│ + Ajouter un poste │
│ │
└──────────────────────────────────────┘
Add Position form (bottom sheet on mobile): - Title (required) - Category (required, dropdown from employee categories) - Department (optional, dropdown from org units of type DEPARTMENT) - Description (optional)
7.5 Contract Type Reference¶
Location: Admin → Paramètres → Types de contrat Read-mostly list — system types are locked, custom can be added:
┌──────────────────────────────────────┐
│ Types de contrat │
│ │
│ ┌──────────────────────────────┐ │
│ │ CDI · Contrat à Durée 🔒│ │
│ │ Indéterminée │ │
│ ├──────────────────────────────┤ │
│ │ CDD · Contrat à Durée 🔒│ │
│ │ Déterminée │ │
│ │ Max: 2 ans │ │ ← Duration info
│ ├──────────────────────────────┤ │
│ │ Stage 🔒│ │
│ │ Max: 2 ans │ │
│ ├──────────────────────────────┤ │
│ │ Apprentissage 🔒│ │
│ │ Max: 3 ans │ │
│ ├──────────────────────────────┤ │
│ │ Journalier 🔒│ │
│ ├──────────────────────────────┤ │
│ │ CTT · Travail Temporaire 🔒│ │
│ │ Max: 2 ans │ │
│ └──────────────────────────────┘ │
│ │
│ + Ajouter un type │
│ │
└──────────────────────────────────────┘
8. Employee Management (Baseline)¶
8.1 Employee List¶
Location in nav: RH → Employés Access: DG, RH Manager, Manager (sees direct reports only) Offline: Full read (list loads from IndexedDB). Create queues for sync.
Layout — Mobile (360px)¶
┌──────────────────────────────────────┐
│ ← Employés [🔍] [+] │
├──────────────────────────────────────┤
│ │
│ 12 employés actifs │
│ │
│ ── Filtres ─────── [Actif ▾] ─── │ ← Status filter chip
│ │
│ ┌──────────────────────────────┐ │
│ │ 👤 Moussa Koné │ │
│ │ EMP-2026-03-001 · Cadre │ │
│ │ Directeur Général │ │
│ │ Direction Générale │ │
│ │ Actif ● │ │ ← Green dot
│ ├──────────────────────────────┤ │
│ │ 👤 Aminata Diallo │ │
│ │ EMP-2026-03-002 · AM │ │
│ │ Responsable RH │ │
│ │ Ressources Humaines │ │
│ │ Actif ● │ │
│ ├──────────────────────────────┤ │
│ │ 👤 Jean Kouamé │ │
│ │ ⏳ Numéro en attente │ │ ← Created offline
│ │ Comptable │ │
│ │ Comptabilité │ │
│ │ Actif ● ○│ │ ← Orange sync dot
│ └──────────────────────────────┘ │
│ │
│ ┌──────────────────────────────┐ │
│ │ + Nouvel employé │ │ ← FAB (Floating Action Button)
│ └──────────────────────────────┘ │
│ │
└──────────────────────────────────────┘
Employee Card States¶
| State | Visual |
|---|---|
| Active | Green dot ● — --color-success |
| Pre-hire | Blue dot ● — --color-info + "Embauche le DD/MM" caption |
| Suspended | Orange dot ● — --color-warning + "Suspendu" badge |
| Terminated | Grey dot ● — --color-text-tertiary + "Fin de contrat" badge |
| On leave (derived) | Green dot + "🏖 En congé" small badge |
| Pending sync | Card has subtle orange left border + small ○ sync icon |
Search (Mobile)¶
Tap 🔍 → full-screen search overlay: - Search by: name, matricule, position, department - Results appear as the user types (debounced 300ms) - Search works offline (queries IndexedDB)
Desktop Layout (1024px+)¶
Table view (not card list):
| Matricule | Nom complet | Poste | Département | Catégorie | Contrat | Statut | Manager |
|---|---|---|---|---|---|---|---|
| EMP-2026-03-001 | Moussa Koné | DG | Direction Gén. | Cadre | CDI | ● Actif | — |
- Column sorting on all headers
- Multi-column filter bar above table: Department dropdown, Status dropdown, Category dropdown, search input
- Bulk actions: not in MVP (V2 with Employee Management)
8.2 Employee Detail View¶
Accessed by: Tap on employee card (mobile) or row (desktop)
Layout — Mobile (360px)¶
┌──────────────────────────────────────┐
│ ← Moussa Koné [✏️] │
├──────────────────────────────────────┤
│ │
│ ┌──────────────────────────────┐ │
│ │ 👤 │ │
│ │ Moussa Koné │ │
│ │ EMP-2026-03-001 │ │
│ │ ● Actif │ │
│ └──────────────────────────────┘ │
│ │
│ ── Informations ──────────────── │
│ │
│ Poste Directeur Général │
│ Département Direction Générale │
│ Catégorie Cadre │
│ Contrat CDI │
│ Date d'embauche 15/01/2020 │
│ Manager — (aucun) │
│ │
│ ── Coordonnées ───────────────── │
│ │
│ E-mail [email protected] │
│ Téléphone +225 07 12 34 56 78 │
│ │
│ ── Module RH Core ────────────── │ ← Upsell section
│ ┌──────────────────────────────┐ │
│ │ 🔒 Dossier complet │ │
│ │ Photo, contacts d'urgence, │ │
│ │ info bancaire, documents… │ │
│ │ │ │
│ │ Souscrire au module RH Core │ │
│ └──────────────────────────────┘ │
│ │
└──────────────────────────────────────┘
8.3 Employee Create/Edit Form¶
Offline: Full create capability. UUID v7 generated client-side. Matricule shows "Numéro en attente" until sync.
Layout — Mobile (360px)¶
┌──────────────────────────────────────┐
│ ← Nouvel employé │
├──────────────────────────────────────┤
│ │
│ Nom complet * │
│ ┌──────────────────────────────┐ │
│ │ │ │
│ └──────────────────────────────┘ │
│ │
│ E-mail │
│ ┌──────────────────────────────┐ │
│ │ │ │ ← Optional
│ └──────────────────────────────┘ │
│ ℹ Pas obligatoire — certains │
│ employés n'ont pas d'e-mail │
│ │
│ Téléphone │
│ ┌─────┬────────────────────────┐ │
│ │+225 │ │ │ ← Optional
│ └─────┴────────────────────────┘ │
│ │
│ Département * │
│ ┌──────────────────────────────┐ │
│ │ Sélectionner… ▾ │ │ ← Dropdown from org tree
│ └──────────────────────────────┘ │
│ │
│ Poste * │
│ ┌──────────────────────────────┐ │
│ │ Rechercher ou créer… │ │ ← Combobox with escape hatch
│ └──────────────────────────────┘ │
│ ℹ Tapez un nouveau poste pour │
│ l'ajouter au référentiel │
│ │
│ Catégorie * │
│ ┌──────────────────────────────┐ │
│ │ (auto-rempli via le poste) │ │ ← Auto-filled from position
│ └──────────────────────────────┘ │
│ ℹ Déterminée par le poste. │
│ Modifiable si nécessaire. │
│ │
│ Type de contrat * │
│ ┌──────────────────────────────┐ │
│ │ CDI ▾ │ │
│ └──────────────────────────────┘ │
│ │
│ Date d'embauche * │
│ ┌──────────────────────────────┐ │
│ │ JJ/MM/AAAA 📅 │ │ ← Date picker
│ └──────────────────────────────┘ │
│ ℹ Si la date est future, │
│ l'employé sera en statut │
│ « Pré-embauche » │
│ │
│ Manager (N+1) │
│ ┌──────────────────────────────┐ │
│ │ Rechercher un employé… ▾ │ │ ← Searchable employee select
│ └──────────────────────────────┘ │
│ ℹ Si non renseigné, les demandes │
│ d'approbation iront à │
│ l'approbateur par défaut │
│ │
│ ┌──────────────────────────────┐ │
│ │ Enregistrer l'employé │ │ ← Primary button
│ └──────────────────────────────┘ │
│ │
└──────────────────────────────────────┘
Position Combobox (Escape Hatch Pattern)¶
The Position field is a combobox — a combined search input + dropdown:
- User starts typing → dropdown shows matching positions from catalog
- If a match exists → user selects it → category auto-fills from the position's linked category
- If NO match exists → dropdown shows: "[typed text] — Ajouter comme nouveau poste"
- Clicking "Ajouter" → inline form expands: "Catégorie pour ce poste : [dropdown]"
- On save → position is created in catalog (is_custom = true) + employee is linked
Why this pattern: Forces structured data (position + category) without forcing the user to pre-configure the catalog. The DG at a 10-person company can type "Chauffeur" and get going — the catalog builds itself.
Form Auto-Save¶
- Each field auto-saves to IndexedDB on blur (even if the full form isn't submitted)
- If the user navigates away mid-form (back button, app switch), data is preserved
- On return, form restores from IndexedDB
- "Brouillon" (Draft) badge appears in the top bar when an incomplete form exists
- Draft can be resumed or discarded
8.4 Employee Form — Desktop (1024px+)¶
Two-column layout: - Left column: Identity (name, email, phone) - Right column: Assignment (department, position, category, contract, hire date, manager) - Full width bottom: Action button
9. User Management & Invitations¶
9.1 User List¶
Location: Admin → Utilisateurs Access: DG and RH Manager Offline: No (users are always created online)
Layout — Mobile (360px)¶
┌──────────────────────────────────────┐
│ ← Utilisateurs [+] │
├──────────────────────────────────────┤
│ │
│ 5 utilisateurs · 3 actifs │
│ │
│ ┌──────────────────────────────┐ │
│ │ 👤 Éric Blonvia │ │
│ │ [email protected] │ │
│ │ DG ● ✓ │ │ ← Active
│ ├──────────────────────────────┤ │
│ │ 👤 Aminata Diallo │ │
│ │ [email protected] │ │
│ │ RH Manager ● ✓ │ │
│ ├──────────────────────────────┤ │
│ │ 📧 [email protected] │ │ ← Invited (no name yet)
│ │ Employé ◌ Invité│ │ ← Hollow dot = invited
│ │ Expiré — Renvoyer → │ │ ← Re-invite link
│ └──────────────────────────────┘ │
│ │
└──────────────────────────────────────┘
9.2 Invite User Flow¶
Tap "+" button → bottom sheet (mobile) / side panel (desktop):
┌──────────────────────────────────────┐
│ ── Inviter un utilisateur ─────── │
│ │
│ Adresse e-mail * │
│ ┌──────────────────────────────┐ │
│ │ │ │
│ └──────────────────────────────┘ │
│ │
│ Rôle * │
│ ┌──────────────────────────────┐ │
│ │ ○ DG (Directeur Général) │ │
│ │ Accès complet │ │
│ │ │ │
│ │ ○ RH Manager │ │
│ │ Gestion employés, congés │ │
│ │ │ │
│ │ ○ Comptable │ │
│ │ Budget, engagements, paie │ │
│ │ │ │
│ │ ○ Employé │ │
│ │ Libre-service uniquement │ │
│ │ │ │
│ │ ○ Manager (Chef de service) │ │
│ │ Approbations équipe │ │
│ └──────────────────────────────┘ │
│ │
│ ┌──────────────────────────────┐ │
│ │ Envoyer l'invitation │ │
│ └──────────────────────────────┘ │
│ │
└──────────────────────────────────────┘
Multi-Tenant User Detection¶
If the email already exists in another tenant: - Show info message: "Cet utilisateur existe déjà sur la plateforme. Il sera ajouté à votre entreprise avec le rôle sélectionné." - No new password email — just a notification: "Vous avez été ajouté à l'entreprise [name]" - User sees new tenant in their "Mes entreprises" switcher
10. Module Gating & Upsell¶
10.1 Navigation Display¶
Unsubscribed modules appear in the sidebar (desktop) and "Plus" bottom sheet (mobile) with distinct styling:
Subscribed module: - Full color icon - Normal text - Clickable → navigates to module
Unsubscribed module:
- 50% opacity icon
- Text in --color-text-tertiary
- Small "✦ Bientôt" badge (for not-yet-released) or "🔒" icon (for released but not subscribed)
- Clickable → opens upsell card (not navigation)
10.2 Module Upsell Card¶
Mobile: Bottom sheet Desktop: Popover card from sidebar
┌──────────────────────────────────────┐
│ │
│ 📅 Gestion de la Paie │
│ │
│ Calculez et générez les bulletins │
│ de paie de vos employés, │
│ conformément au Code du Travail │
│ ivoirien. │
│ │
│ ✓ Calcul automatique ITS + CNPS │
│ ✓ Bulletins de paie PDF │
│ ✓ Livre de paie mensuel │
│ ✓ Déclarations sociales │
│ │
│ À partir de 30 000 FCFA/mois │
│ │
│ ── Vous êtes administrateur ? ── │
│ │
│ ┌──────────────────────────────┐ │
│ │ Souscrire ce module │ │ ← Admin only → goes to §11
│ └──────────────────────────────┘ │
│ │
│ ── Vous êtes employé ? ────────── │
│ │
│ Contactez votre administrateur │
│ pour activer ce module. │
│ │
└──────────────────────────────────────┘
Logic:
- IF user has role DG or permission cp.tenant.manage → show "Souscrire" button
- IF user is regular employee → show "Contactez votre administrateur" text
- Module descriptions and feature lists are hardcoded per module (content managed, not DB-driven for MVP)
11. Billing & Subscription Management¶
11.1 Subscription Dashboard¶
Location: Admin → Abonnement Access: DG only Offline: No (billing is always online)
Layout — Mobile (360px)¶
┌──────────────────────────────────────┐
│ ← Abonnement │
├──────────────────────────────────────┤
│ │
│ ── Votre abonnement ──────────── │
│ │
│ ┌──────────────────────────────┐ │
│ │ Statut: ● Actif │ │
│ │ Segment: S1 (2-12 salariés) │ │
│ │ Prochaine échéance: │ │
│ │ 15/03/2026 (17 jours) │ │
│ └──────────────────────────────┘ │
│ │
│ ── Modules souscrits ─────────── │
│ │
│ ┌──────────────────────────────┐ │
│ │ ✓ Absences 12 000 FCFA│ │
│ │ ✓ Présence QR 5 000 FCFA│ │
│ │ ─────────────────────────── │ │
│ │ Pack Contrôle 15 000 FCFA│ │
│ │ Économie: -2 000 FCFA│ │
│ │ ─────────────────────────── │ │
│ │ Total mensuel 15 000 FCFA│ │
│ └──────────────────────────────┘ │
│ │
│ ┌──────────────────────────────┐ │
│ │ + Ajouter un module │ │ ← Goes to module catalog
│ └──────────────────────────────┘ │
│ │
│ ── Méthode de paiement ────────── │
│ │
│ ┌──────────────────────────────┐ │
│ │ 📱 Orange Money │ │
│ │ +225 07 XX XX XX XX │ │
│ │ Modifier → │ │
│ └──────────────────────────────┘ │
│ │
│ ── Historique des factures ────── │
│ │
│ ┌──────────────────────────────┐ │
│ │ FAC-2026-00001 · Fév. 2026 │ │
│ │ 15 000 FCFA ● Payée │ │
│ │ PDF ↓ → │ │
│ ├──────────────────────────────┤ │
│ │ FAC-2026-00002 · Mars 2026 │ │
│ │ 15 000 FCFA ◌ En attente│ │
│ │ Payer maintenant → │ │
│ └──────────────────────────────┘ │
│ │
└──────────────────────────────────────┘
11.2 Add Module Flow¶
From "Ajouter un module" button → module catalog screen (similar to Step 2 of onboarding, §3.2): - Shows all available modules with current prices for the tenant's segment - Selected modules appear as "selected" - New module selection shows price delta: "+12 000 FCFA/mois" - Pack detection runs in real-time - Confirmation: "Votre abonnement sera mis à jour à la prochaine échéance." - Payment for the delta is not charged mid-cycle (MVP simplification)
11.3 Module Deactivation¶
From subscription dashboard, tap a subscribed module → detail:
┌──────────────────────────────────────┐
│ │
│ Désactiver « Présence QR » ? │
│ │
│ ⚠ Vos données de pointage │
│ resteront accessibles en │
│ lecture seule. │
│ │
│ ⚠ Le Pack Contrôle ne sera │
│ plus applicable. Votre │
│ tarif Absences repassera à │
│ 12 000 FCFA/mois. │
│ │
│ ┌──────────────────────────────┐ │
│ │ Confirmer la │ │
│ │ désactivation │ │ ← Destructive secondary button
│ └──────────────────────────────┘ │
│ │
│ ┌──────────────────────────────┐ │
│ │ Annuler │ │ ← Primary button (keep module)
│ └──────────────────────────────┘ │
│ │
└──────────────────────────────────────┘
Undo: After confirmation, 10-second undo toast: "Module désactivé. Annuler ?"
12. Audit Trail Viewer¶
12.1 Audit Log Screen¶
Location: Admin → Audit Access: DG only (tenant-scoped view) Offline: No
Layout — Mobile (360px)¶
┌──────────────────────────────────────┐
│ ← Journal d'audit │
├──────────────────────────────────────┤
│ │
│ ── Filtres ───────────────────── │
│ [Module ▾] [Action ▾] [Date ▾] │ ← Filter chips
│ │
│ ┌──────────────────────────────┐ │
│ │ 26/02/2026 14:32 │ │
│ │ Éric Blonvia │ │
│ │ Employé créé │ │ ← Human-readable action
│ │ « Jean Kouamé » │ │
│ │ Module: Employés │ │
│ │ Détails → │ │
│ ├──────────────────────────────┤ │
│ │ 26/02/2026 10:15 │ │
│ │ Aminata Diallo │ │
│ │ Département modifié │ │
│ │ « Production » → « Prod. » │ │ ← Before → After summary
│ │ Module: Structure │ │
│ │ Détails → │ │
│ └──────────────────────────────┘ │
│ │
│ Charger plus… │ ← Pagination (50 per page)
│ │
└──────────────────────────────────────┘
Audit Detail View¶
Tap "Détails" → bottom sheet (mobile) / side panel (desktop) showing the full before/after JSON diff in a human-readable format:
┌──────────────────────────────────────┐
│ ── Détail de l'audit ──────────── │
│ │
│ Action: Modification │
│ Entité: Département │
│ Par: Aminata Diallo │
│ Date: 26/02/2026 à 10:15 │
│ │
│ ── Modifications ──────────────── │
│ │
│ Nom │
│ Avant: Production │
│ Après: Prod. │
│ │
└──────────────────────────────────────┘
12.2 Audit Log — Desktop (1024px+)¶
Full-width table with columns: Date/Heure, Utilisateur, Action, Entité, Module, Résumé. Expandable rows showing before/after diff inline. Advanced filters: date range picker, module dropdown, action type checkboxes, user search.
13. Multi-Tenant Switcher¶
13.1 Tenant Switcher (Cabinet Comptable / Multi-Tenant Users)¶
Trigger: User avatar in top bar → "Mes entreprises" option
Layout — Mobile (full-screen bottom sheet)¶
┌──────────────────────────────────────┐
│ ── Mes entreprises ───────────── │
│ │
│ ┌──────────────────────────────┐ │
│ │ [Logo] Acme SARL │ │
│ │ ✓ Entreprise active │ │ ← Current tenant (highlighted)
│ │ DG │ │
│ ├──────────────────────────────┤ │
│ │ [Logo] Pharma Plus CI │ │
│ │ Comptable │ │
│ ├──────────────────────────────┤ │
│ │ [Logo] Trans Express │ │
│ │ Comptable │ │
│ ├──────────────────────────────┤ │
│ │ [Logo] Resto Le Palmier │ │
│ │ Comptable │ │
│ └──────────────────────────────┘ │
│ │
│ Tapez sur une entreprise pour │
│ changer de contexte. │
│ │
└──────────────────────────────────────┘
Behavior: - Tap a tenant → full-screen loading overlay: "Chargement de [tenant name]…" (token exchange happening) - New JWT issued → all cached data replaced → redirect to Dashboard of new tenant - Previous tenant context is cleared from memory - Switch takes < 2 seconds
Desktop Layout¶
Dropdown from user avatar menu (not a separate page): - Shows tenant list with logos, names, and user's role per tenant - Current tenant has checkmark - Click to switch — same token exchange flow
13.2 Home Tenant Dashboard (Multi-Tenant User Login)¶
When a user with multiple tenants logs in:
- They land on their home_tenant_id dashboard
- The "Mes entreprises" section appears as a card on the Dashboard (not just in the user menu)
- Shows thumbnail cards for each tenant with: logo, name, role, quick-switch tap
14. Tenant Status Banners¶
Persistent, context-sensitive banners appear at the top of the content area (below the top bar) based on tenant status. These are not toasts — they persist until the condition is resolved.
14.1 Banner Specifications¶
| Tenant Status | Banner Color | Message | Dismissible? | CTA |
|---|---|---|---|---|
| TRIAL | --color-info-light + --color-info border |
"Période d'essai : [X] jours restants" | No | "Souscrire maintenant" (admin) / none (employee) |
| PAYMENT_REQUIRED | --color-warning-light + --color-warning border |
"Modules en lecture seule. Finalisez votre paiement pour activer toutes les fonctionnalités." | No | "Payer maintenant" (admin) |
| ACTIVE_PAYMENT_PENDING | --color-info-light + --color-info border |
"Virement en attente de confirmation. [X] jours restants." | Yes (once per session) | "Payer par Mobile Money" (admin) |
| ACTIVE_INCOMPLETE | --color-warning-light + --color-warning border |
"Veuillez compléter vos informations légales (RCCM, NIF) dans les paramètres." | Yes (once per day) | "Compléter →" (admin) |
| ACTIVE_INCOMPLETE (3 months, read-only) | --color-error-light + --color-error border |
"Accès en lecture seule. Complétez vos informations légales pour restaurer l'accès complet." | No | "Compléter →" (admin) |
| SUSPENDED | --color-error-light + --color-error border |
"Compte suspendu. Vos données sont préservées. Renouvelez votre abonnement pour restaurer l'accès." | No | "Renouveler →" (admin) |
14.2 Banner Layout¶
┌──────────────────────────────────────┐
│ ⚠ Période d'essai : 10 jours │
│ restants. [Souscrire →] │
│ [✕] │ ← If dismissible
└──────────────────────────────────────┘
- Height: auto (wraps content, typically 48-64px)
- Full width of content area
- Below top bar, above page content
- Max one banner visible at a time (highest priority wins)
- Priority order: SUSPENDED > ACTIVE_INCOMPLETE (read-only) > PAYMENT_REQUIRED > ACTIVE_INCOMPLETE > TRIAL > ACTIVE_PAYMENT_PENDING
15. Admin Console (Separate App)¶
15.1 Design Language — Admin Console¶
The Admin Console is a separate React application with a different design language from Papillon.
| Aspect | Papillon (tenant) | Admin Console (ALTARYS) |
|---|---|---|
| Users | HR managers, employees | 3-5 ALTARYS operators |
| Device | Phone-first (360px) | Desktop only (1024px+) |
| Offline | Mandatory (PWA) | Not needed |
| Aesthetic | Warm amber/teal | Neutral grey/blue |
| Density | Low (generous whitespace) | Medium (data-dense tables) |
| Primary color | #F59E0B (amber) |
#1E3A5F (navy) |
| Accent | #0D6B6E (teal) |
#2563EB (blue) |
| Background | #FFFDF7 (warm off-white) |
#F9FAFB (cool light grey) |
| Typography | Inter 16px body | Inter 14px body (denser) |
| Tone | "Votre assistant RH de confiance" | "Plateforme d'administration ALTARYS" |
The Admin Console does NOT use Papillon design tokens. It has its own minimal token set:
| Token | Value | Usage |
|---|---|---|
--admin-primary |
#1E3A5F |
Headers, primary actions |
--admin-accent |
#2563EB |
Links, active states |
--admin-bg |
#F9FAFB |
Page background |
--admin-surface |
#FFFFFF |
Cards, panels |
--admin-border |
#E5E7EB |
Borders, dividers |
--admin-text |
#111827 |
Primary text |
--admin-text-secondary |
#6B7280 |
Secondary text |
--admin-success |
#059669 |
Active, paid, healthy |
--admin-warning |
#D97706 |
Pending, attention needed |
--admin-error |
#DC2626 |
Suspended, failed, critical |
15.2 Tenant List (Admin Dashboard)¶
The main screen ALTARYS operators see daily. Dense, filterable, sortable.
Layout — Desktop (1024px+)¶
┌──────────────────────────────────────────────────────────────────────────────┐
│ ALTARYS Admin [🔔] [👤 Admin] │
├──────────┬───────────────────────────────────────────────────────────────────┤
│ │ │
│ 📊 Tableau│ ── Aperçu rapide ───────────────────────────────────────────── │
│ de bord│ ┌────────┐ ┌────────┐ ┌────────┐ ┌────────┐ ┌────────────┐ │
│ │ │ 142 │ │ 12 │ │ 5 │ │ 1 845 │ │ 2.4M FCFA │ │
│ 🏢 Tenants│ │ Tenants │ │Paiements│ │Suspendus│ │Employés│ │MRR │ │
│ │ │ actifs │ │en att. │ │ │ │ total │ │ │ │
│ 💳 Paie- │ └────────┘ └────────┘ └────────┘ └────────┘ └────────────┘ │
│ ments │ │
│ │ ── Tenants ──────────────── [🔍 Rechercher… ] [Exporter ↓] │
│ 📊 Statis-│ [Statut ▾] [Segment ▾] [Canal ▾] [Date ▾] │
│ tiques│ │
│ │ ┌──────┬───────────┬──────┬─────┬──────┬──────┬────────────────┐│
│ ⚙️ Config │ │Status │ Entreprise│ Seg. │Empl.│Canal │ Créé │ Paiement ││
│ pays │ ├──────┼───────────┼──────┼─────┼──────┼──────┼────────────────┤│
│ │ │● ACTIF│ Acme SARL │ S1 │ 12 │ Self │15/01 │ ● Payé ││
│ │ │● ACTIF│ Pharma+ │ S3 │ 45 │ CRM │20/01 │ ● Payé ││
│ │ │◐ ESSAI│ TechCI │ S1 │ 5 │ Self │24/02 │ ◌ Essai (8j) ││
│ │ │⚠ PEND.│ Transport │ S2 │ 20 │ CRM │25/02 │ ⚠ Virement att.││
│ │ │✕ SUSP.│ OldCorp │ S1 │ 8 │ Self │01/11 │ ✕ Impayé 22j ││
│ │ └──────┴───────────┴──────┴─────┴──────┴──────┴────────────────┘│
│ │ │
│ │ Afficher 1-20 sur 142 [< 1 2 3 ... 8 >] │
│ │ │
└──────────┴───────────────────────────────────────────────────────────────────┘
200px Remaining width
Table Row Status Icons¶
| Status | Icon | Color |
|---|---|---|
| ACTIVE | ● |
--admin-success |
| TRIAL | ◐ |
--admin-accent |
| ACTIVE_INCOMPLETE | ● |
--admin-warning |
| ACTIVE_PAYMENT_PENDING | ⚠ |
--admin-warning |
| PAYMENT_REQUIRED | ⚠ |
--admin-warning |
| SUSPENDED | ✕ |
--admin-error |
| DELETED | ◌ |
--admin-text-secondary |
| PENDING | ◌ |
--admin-text-secondary |
| PENDING_VERIFICATION | ◌ |
--admin-text-secondary |
15.3 Tenant Detail (Admin)¶
Click a tenant row → side panel or full page with tabs:
Tabs: Informations | Modules | Paiements | Audit | Actions
Informations tab: - Company: name, RCCM, NIF, country, address, sector - Admin: name, email, phone - Config: segment, DB profile, onboarding channel, salesperson ID, dates (created, activated, suspended) - Status badge with state machine context
Modules tab: - List of all modules with status per module (ACTIVE / INACTIVE / TRIAL) - "Activer" / "Désactiver" toggle per module (with confirmation) - Override capability: "Accorder un accès temporaire" (with expiry date)
Paiements tab: - Invoice list with statuses - "Confirmer le paiement" button for pending bank transfers - Manual payment recording form
Audit tab: - Tenant-specific audit trail (filtered view of global audit)
Actions tab: - "Suspendre ce tenant" (requires reason text input) - "Réactiver ce tenant" - "Supprimer ce tenant" (soft delete — requires typed confirmation: company name)
15.4 Pending Payments Dashboard (Admin)¶
Critical daily-use screen for ALTARYS operations.
┌────────────────────────────────────────────────────────────────────┐
│ Paiements en attente Auto-refresh: 5min │
├────────────────────────────────────────────────────────────────────┤
│ │
│ ── Virements en attente (5) ────────────────────────────────── │
│ │
│ ┌──────────┬──────────┬──────────┬──────┬──────────────────────┐ │
│ │Entreprise│ Montant │ Créé le │ Reste│ Action │ │
│ ├──────────┼──────────┼──────────┼──────┼──────────────────────┤ │
│ │Transport │15 000 FCFA│20/02/2026│ 4j │[Confirmer] [Relancer]│ │
│ │LogiCI │25 000 FCFA│22/02/2026│ 6j │[Confirmer] [Relancer]│ │
│ └──────────┴──────────┴──────────┴──────┴──────────────────────┘ │
│ │
│ ── Paiements échoués (2) ──────────────────────────────────── │
│ │
│ ┌──────────┬──────────┬──────────┬──────────────────────────────┐│
│ │Entreprise│ Montant │ Échoué │ Action ││
│ ├──────────┼──────────┼──────────┼──────────────────────────────┤│
│ │BoutiqueCI│15 000 FCFA│25/02/2026│[Renvoyer lien] [Marquer payé]││
│ └──────────┴──────────┴──────────┴──────────────────────────────┘│
│ │
│ ── Factures impayées (3) ──────────────────────────────────── │
│ ... │
│ │
└────────────────────────────────────────────────────────────────────┘
"Confirmer" action: 1. Click → confirmation dialog: "Confirmez-vous la réception du virement de [amount] de [company] ?" 2. On confirm → Invoice status → PAID, Tenant status updated per state machine 3. Audit entry created with admin's user_id 4. Email notification sent to tenant: "Paiement confirmé"
15.5 Module Override (Admin)¶
From tenant detail → Modules tab:
- Toggle module ON/OFF for any tenant
- "Accès promotionnel" option: activate module with expiry date (promotional access for demos/trials)
- All overrides recorded in audit trail with admin user_id and reason
15.6 Country Configuration Editor (Admin)¶
Accessed: Admin → Config Pays Usage: Rare (when tax rates change, holidays are updated)
Two-panel layout: - Left: Country selector (CI for MVP) + config categories (Tax, Social Contributions, Leave Types, Holidays, Categories, Contract Types, Salary Grids) - Right: Editable data table for selected category
Special UI: Unverified rates (is_verified = false) displayed with orange background and "⚠ Non vérifié" badge. Admin can toggle is_verified after confirming with official sources.
15.7 Platform Metrics (Admin)¶
Simple KPI dashboard:
| Metric | Display |
|---|---|
| Total tenants by status | Horizontal stacked bar |
| Total active employees | Big number with trend |
| MRR (Monthly Recurring Revenue) | Big number with trend |
| Module popularity | Horizontal bar chart (modules ranked by subscription count) |
| Tenant growth | Line chart (new tenants per week, last 12 weeks) |
| Payment method split | Pie chart (Mobile Money vs. Bank Transfer) |
16. Offline Behavior Specifications¶
16.1 Offline Capability Matrix¶
| Screen / Feature | Offline Read | Offline Write | Sync Behavior |
|---|---|---|---|
| Employee List | ✅ Full (IndexedDB) | — | Prefetched on login |
| Employee Create | — | ✅ Full (UUID v7) | Queue → POST on reconnect |
| Employee Edit | ✅ Current data | ✅ Edits queued | Last-write-wins (with conflict detection) |
| Org Structure | ✅ Full tree | ✅ Add units | Queue → POST on reconnect |
| Position Catalog | ✅ Full list | ✅ Add positions | Queue → POST on reconnect |
| Company Settings | ✅ Read | ❌ | Requires connectivity |
| User Management | ❌ | ❌ | Always online |
| Billing/Payment | ❌ | ❌ | Always online |
| Audit Trail | ❌ | — | Always online |
| Module Catalog | ✅ Cached descriptions | ❌ | Always online for actions |
| Tenant Switcher | ❌ | ❌ | Requires token exchange |
| Registration | ❌ | ❌ | Always online |
16.2 Sync Conflict Resolution¶
When an employee record is edited offline and conflicts with a server update:
┌──────────────────────────────────────┐
│ ⚠ Conflit de synchronisation │
│ │
│ L'employé « Jean Kouamé » a été │
│ modifié sur un autre appareil. │
│ │
│ ── Votre version ──────────────── │
│ Département: Commercial │
│ (modifié le 26/02 à 14:30) │
│ │
│ ── Version du serveur ─────────── │
│ Département: Production │
│ (modifié le 26/02 à 14:15 par │
│ Aminata Diallo) │
│ │
│ ┌──────────────────────────────┐ │
│ │ Garder ma version │ │ ← Overwrites server
│ └──────────────────────────────┘ │
│ ┌──────────────────────────────┐ │
│ │ Garder la version serveur │ │ ← Discards local change
│ └──────────────────────────────┘ │
│ │
└──────────────────────────────────────┘
16.3 Prefetch Strategy¶
On login (or app open with valid token): 1. Immediate: Employee list, org structure tree, position catalog, contract types, categories 2. Background: Tenant settings, module list, notification count, permission matrix 3. On-demand: Audit trail, billing data, user list (not cached)
17. Responsive Behavior Summary¶
Breakpoints (from host-shell-design.md)¶
| Breakpoint | Width | Layout Pattern |
|---|---|---|
| Phone | 360px | Single column, bottom sheet modals, bottom nav |
| Tablet | 768px | Collapsed sidebar (icons), content fills remaining width |
| Desktop | 1024px | Expanded sidebar (260px), master-detail panels |
| Large Desktop | 1440px | Same as desktop, content centered in max-width 1200px |
Per-Screen Responsive Table¶
| Screen | Phone (360) | Tablet (768) | Desktop (1024+) |
|---|---|---|---|
| Registration | Single column card | Single column card (wider) | Split: branding left, form right |
| Module Selection | Stacked cards | 2-column card grid | 3-column card grid |
| Payment Choice | Stacked options | 2-column options | 2-column with summary sidebar |
| Company Settings | Single column form | Two column form | Two column form |
| Org Structure | Indented list | Tree with detail bottom sheet | Master (tree) + detail panel |
| Employee List | Card list | Card list (2 columns) | Data table |
| Employee Form | Single column | Two column | Two column |
| Employee Detail | Stacked sections | Two column | Two column + sidebar |
| User List | Card list | Table | Table |
| Subscription | Stacked cards | Two column | Two column + sidebar |
| Audit Trail | Timeline list | Table (compact) | Full table with filters |
| Tenant Switcher | Full screen bottom sheet | Modal overlay | Dropdown from avatar |
18. French Micro-copy Document¶
18.1 Registration & Onboarding¶
| Key | French Text |
|---|---|
registration.title |
"Créez votre compte Papillon en 5 minutes" |
registration.subtitle |
"Simplifiez la gestion de vos ressources humaines" |
registration.company_name.label |
"Nom de l'entreprise" |
registration.company_name.placeholder |
"Ex : Acme SARL" |
registration.country.label |
"Pays" |
registration.employee_count.label |
"Nombre de salariés" |
registration.employee_count.placeholder |
"Sélectionnez une tranche" |
registration.admin_name.label |
"Votre nom complet" |
registration.admin_name.placeholder |
"Ex : Moussa Koné" |
registration.email.label |
"Adresse e-mail" |
registration.email.placeholder |
"[email protected]" |
registration.phone.label |
"Numéro de téléphone" |
registration.phone.placeholder |
"07 12 34 56 78" |
registration.rccm.label |
"RCCM (optionnel)" |
registration.rccm.helper |
"Vous pourrez le fournir plus tard" |
registration.trial.label |
"Démarrer un essai gratuit de 14 jours" |
registration.submit |
"Continuer →" |
registration.already_registered |
"Déjà inscrit ?" |
registration.login_link |
"Se connecter" |
registration.duplicate_email |
"Un compte existe déjà avec cet e-mail." |
registration.duplicate_phone |
"Un compte existe déjà avec ce numéro." |
registration.rate_limited |
"Trop de tentatives. Veuillez réessayer dans quelques minutes." |
registration.server_error |
"Une erreur est survenue. Veuillez réessayer." |
18.2 Module Selection¶
| Key | French Text |
|---|---|
modules.title |
"Choisissez vos modules" |
modules.subtitle |
"Sélectionnez au moins 1 module. Vous pourrez en ajouter plus tard." |
modules.available_now |
"Disponible maintenant" |
modules.coming_soon |
"Bientôt disponible" |
modules.pack_detected |
"Pack {packName} détecté · -{discount}%" |
modules.summary |
"{count} module(s) · {price} FCFA/mois" |
modules.continue |
"Continuer →" |
modules.subscribe |
"Souscrire" |
modules.contact_admin |
"Contactez votre administrateur pour activer ce module." |
18.3 Payment¶
| Key | French Text |
|---|---|
payment.title |
"Comment souhaitez-vous payer ?" |
payment.mobile_money.title |
"Paiement Mobile Money" |
payment.mobile_money.providers |
"Orange Money, Wave, MTN Money" |
payment.mobile_money.instant |
"Paiement instantané. Accès immédiat." |
payment.mobile_money.button |
"Payer {amount} FCFA" |
payment.bank_transfer.title |
"Virement bancaire" |
payment.bank_transfer.delay |
"Délai de traitement : 10 jours maximum. Accès complet pendant cette période." |
payment.bank_transfer.button |
"Choisir le virement" |
payment.trial.title |
"Essai gratuit 14 jours" |
payment.trial.subtitle |
"Testez avant de payer." |
payment.trial.link |
"Démarrer l'essai →" |
payment.processing |
"Veuillez confirmer le paiement sur votre téléphone" |
payment.success |
"Paiement confirmé ! Bienvenue sur Papillon." |
payment.failed |
"Le paiement a échoué. Veuillez réessayer." |
payment.timeout |
"Le paiement prend plus de temps que prévu. Nous vous notifierons par e-mail dès confirmation." |
18.4 Verification & Status¶
| Key | French Text |
|---|---|
verification.email_sent |
"Un e-mail de vérification a été envoyé à {email}" |
verification.check_inbox |
"Vérifiez votre boîte de réception (et les spams)" |
verification.success |
"Adresse e-mail confirmée !" |
verification.expired |
"Ce lien a expiré." |
verification.resend |
"Renvoyer un e-mail de vérification" |
verification.invalid |
"Ce lien n'est pas valide." |
verification.already_done |
"Votre adresse est déjà confirmée." |
18.5 Tenant Status Banners¶
| Key | French Text |
|---|---|
banner.trial |
"Période d'essai : {days} jour(s) restant(s)" |
banner.trial.cta |
"Souscrire maintenant" |
banner.payment_required |
"Modules en lecture seule. Finalisez votre paiement pour activer toutes les fonctionnalités." |
banner.payment_required.cta |
"Payer maintenant" |
banner.payment_pending |
"Virement en attente de confirmation. {days} jour(s) restant(s)." |
banner.payment_pending.cta |
"Payer par Mobile Money" |
banner.incomplete |
"Veuillez compléter vos informations légales (RCCM, NIF) dans les paramètres de votre entreprise." |
banner.incomplete.cta |
"Compléter →" |
banner.incomplete_readonly |
"Accès en lecture seule. Complétez vos informations légales pour restaurer l'accès complet." |
banner.suspended |
"Compte suspendu. Vos données sont préservées. Renouvelez votre abonnement pour restaurer l'accès." |
banner.suspended.cta |
"Renouveler →" |
18.6 Employee Management¶
| Key | French Text |
|---|---|
employee.list.title |
"Employés" |
employee.list.count |
"{count} employé(s) actif(s)" |
employee.list.empty |
"Aucun employé pour le moment. Ajoutez votre premier collaborateur !" |
employee.list.empty.cta |
"Ajouter un employé" |
employee.create.title |
"Nouvel employé" |
employee.edit.title |
"Modifier l'employé" |
employee.form.name.label |
"Nom complet" |
employee.form.email.label |
"E-mail" |
employee.form.email.helper |
"Pas obligatoire — certains employés n'ont pas d'e-mail" |
employee.form.phone.label |
"Téléphone" |
employee.form.department.label |
"Département" |
employee.form.department.placeholder |
"Sélectionner…" |
employee.form.position.label |
"Poste" |
employee.form.position.placeholder |
"Rechercher ou créer…" |
employee.form.position.helper |
"Tapez un nouveau poste pour l'ajouter au référentiel" |
employee.form.category.label |
"Catégorie" |
employee.form.category.helper |
"Déterminée par le poste. Modifiable si nécessaire." |
employee.form.contract.label |
"Type de contrat" |
employee.form.hire_date.label |
"Date d'embauche" |
employee.form.hire_date.helper_future |
"Si la date est future, l'employé sera en statut « Pré-embauche »" |
employee.form.manager.label |
"Manager (N+1)" |
employee.form.manager.placeholder |
"Rechercher un employé…" |
employee.form.manager.helper |
"Si non renseigné, les demandes d'approbation iront à l'approbateur par défaut" |
employee.form.submit |
"Enregistrer l'employé" |
employee.created.online |
"Employé créé ✓" |
employee.created.offline |
"Employé enregistré hors ligne ●" |
employee.matricule.pending |
"Numéro en attente" |
employee.status.active |
"Actif" |
employee.status.pre_hire |
"Pré-embauche" |
employee.status.suspended |
"Suspendu" |
employee.status.terminated |
"Fin de contrat" |
employee.status.on_leave |
"En congé" |
employee.no_manager_alert |
"L'employé {name} n'a pas de responsable assigné. Veuillez assigner un N+1." |
18.7 Organization & Settings¶
| Key | French Text |
|---|---|
org.title |
"Structure de l'entreprise" |
org.add_unit |
"Ajouter une unité" |
org.unit_type.entity |
"Entité" |
org.unit_type.site |
"Site / Établissement" |
org.unit_type.department |
"Département / Service" |
org.deactivate |
"Désactiver" |
org.deactivate.confirm |
"Les employés rattachés ne seront pas affectés, mais aucune nouvelle affectation ne sera possible." |
settings.title |
"Paramètres de l'entreprise" |
settings.saved |
"Enregistré ✓" |
settings.saved_offline |
"Modification enregistrée hors ligne" |
settings.default_approver.label |
"Approbateur par défaut" |
settings.default_approver.helper |
"Reçoit les demandes si un employé n'a pas de manager" |
settings.matricule_preview |
"Aperçu : {prefix}-{YYYY}-{MM}-{example}" |
18.8 Billing & Subscription¶
| Key | French Text |
|---|---|
billing.title |
"Abonnement" |
billing.status |
"Statut" |
billing.segment |
"Segment : {code} ({range} salariés)" |
billing.next_due |
"Prochaine échéance : {date} ({days} jours)" |
billing.modules_subscribed |
"Modules souscrits" |
billing.pack_applied |
"Pack {name} appliqué" |
billing.savings |
"Économie : -{amount} FCFA" |
billing.total_monthly |
"Total mensuel : {amount} FCFA" |
billing.add_module |
"Ajouter un module" |
billing.payment_method |
"Méthode de paiement" |
billing.change_method |
"Modifier" |
billing.invoices |
"Historique des factures" |
billing.invoice.paid |
"Payée" |
billing.invoice.pending |
"En attente" |
billing.invoice.overdue |
"En retard" |
billing.deactivate.title |
"Désactiver « {module} » ?" |
billing.deactivate.data_warning |
"Vos données resteront accessibles en lecture seule." |
billing.deactivate.pack_warning |
"Le Pack {name} ne sera plus applicable. Votre tarif {module} repassera à {price} FCFA/mois." |
billing.deactivate.confirm |
"Confirmer la désactivation" |
billing.deactivate.undo |
"Module désactivé. Annuler ?" |
18.9 User Management¶
| Key | French Text |
|---|---|
users.title |
"Utilisateurs" |
users.count |
"{total} utilisateur(s) · {active} actif(s)" |
users.invite |
"Inviter un utilisateur" |
users.invite.email.label |
"Adresse e-mail" |
users.invite.role.label |
"Rôle" |
users.invite.submit |
"Envoyer l'invitation" |
users.invite.success |
"Invitation envoyée à {email}" |
users.invite.existing_user |
"Cet utilisateur existe déjà sur la plateforme. Il sera ajouté à votre entreprise avec le rôle sélectionné." |
users.status.active |
"Actif" |
users.status.invited |
"Invité" |
users.status.disabled |
"Désactivé" |
users.status.expired |
"Expiré — Renvoyer" |
users.role.dg |
"DG (Directeur Général)" |
users.role.dg.desc |
"Accès complet" |
users.role.rh |
"RH Manager" |
users.role.rh.desc |
"Gestion employés, congés, paie" |
users.role.comptable |
"Comptable" |
users.role.comptable.desc |
"Budget, engagements, notes de frais" |
users.role.employee |
"Employé" |
users.role.employee.desc |
"Libre-service uniquement" |
users.role.manager |
"Manager (Chef de service)" |
users.role.manager.desc |
"Approbations équipe" |
18.10 Audit Trail¶
| Key | French Text |
|---|---|
audit.title |
"Journal d'audit" |
audit.filter.module |
"Module" |
audit.filter.action |
"Action" |
audit.filter.date |
"Période" |
audit.action.create |
"Création" |
audit.action.update |
"Modification" |
audit.action.delete |
"Suppression" |
audit.detail.title |
"Détail de l'audit" |
audit.detail.action |
"Action" |
audit.detail.entity |
"Entité" |
audit.detail.by |
"Par" |
audit.detail.date |
"Date" |
audit.detail.changes |
"Modifications" |
audit.detail.before |
"Avant" |
audit.detail.after |
"Après" |
audit.load_more |
"Charger plus…" |
18.11 Multi-Tenant¶
| Key | French Text |
|---|---|
tenant_switcher.title |
"Mes entreprises" |
tenant_switcher.current |
"Entreprise active" |
tenant_switcher.switching |
"Chargement de {name}…" |
tenant_switcher.hint |
"Tapez sur une entreprise pour changer de contexte." |
18.12 Empty States¶
| Key | French Text |
|---|---|
empty.employees |
"Aucun employé pour le moment.\nAjoutez votre premier collaborateur !" |
empty.employees.cta |
"Ajouter un employé" |
empty.org_units |
"Votre structure organisationnelle est vide.\nCommencez par ajouter des départements." |
empty.org_units.cta |
"Ajouter un département" |
empty.positions |
"Aucun poste défini.\nLes postes seront créés automatiquement lorsque vous ajouterez des employés." |
empty.users |
"Invitez vos collaborateurs pour qu'ils puissent accéder à Papillon." |
empty.users.cta |
"Inviter un utilisateur" |
empty.invoices |
"Aucune facture pour le moment." |
empty.audit |
"Aucune activité enregistrée pour cette période." |
18.13 Sync & Offline¶
| Key | French Text |
|---|---|
sync.synced |
"Synchronisé" |
sync.pending |
"{count} modification(s) en attente" |
sync.syncing |
"Synchronisation en cours…" |
sync.offline |
"Hors ligne" |
sync.last_synced |
"Dernière sync : {time}" |
sync.conflict.title |
"Conflit de synchronisation" |
sync.conflict.description |
"L'élément « {name} » a été modifié sur un autre appareil." |
sync.conflict.keep_mine |
"Garder ma version" |
sync.conflict.keep_server |
"Garder la version serveur" |
sync.conflict.your_version |
"Votre version" |
sync.conflict.server_version |
"Version du serveur" |
19. New Component Specifications¶
19.1 StepIndicator¶
Purpose: Shows progress through multi-step flows (registration).
| Prop | Type | Default |
|---|---|---|
| steps | { label: string }[] |
Required |
| currentStep | number |
Required |
States:
- Completed step: --color-primary filled circle + solid line
- Current step: --color-primary filled circle, pulsing ring
- Future step: --color-border hollow circle + dashed line
Accessibility: aria-current="step" on current, aria-label="Étape {n} sur {total}: {label}"
19.2 ModuleCard¶
Purpose: Displays a module in selection / upsell contexts.
| Prop | Type | Default |
|---|---|---|
| name | string |
Required |
| description | string |
Required |
| icon | ReactNode |
Required |
| price | string |
Required |
| available | boolean |
true |
| selected | boolean |
false |
| locked | boolean |
false |
| comingSoonDate | string \| null |
null |
| onSelect | () => void |
— |
States:
- Available, unselected: --color-bg-secondary bg, --color-border border
- Available, selected: --color-primary-light bg, --color-primary border, checkmark
- Locked: 60% opacity, lock icon, "Bientôt · {date}" badge
- Disabled: not applicable (all cards are tappable)
19.3 TenantStatusBanner¶
Purpose: Persistent banner based on tenant status.
| Prop | Type | Default |
|---|---|---|
| status | TenantStatus |
Required |
| daysRemaining | number \| null |
— |
| ctaAction | () => void |
— |
| onDismiss | (() => void) \| null |
null (non-dismissible) |
| isAdmin | boolean |
false |
Rendering: Full width, below top bar, sticky. Height auto. Max one visible.
19.4 OrgTreeNode¶
Purpose: Renders a node in the organisational tree.
| Prop | Type | Default |
|---|---|---|
| unit | OrgUnit |
Required |
| depth | number |
0 |
| isExpanded | boolean |
false |
| onToggle | () => void |
— |
| onSelect | () => void |
— |
| onAdd | () => void |
— |
Icons by type:
- ENTITY: 🏢 (building)
- SITE: 📍 (pin)
- DEPARTMENT: 🏛 (institution)
19.5 PositionCombobox¶
Purpose: Combined search + create input for position assignment.
| Prop | Type | Default |
|---|---|---|
| positions | Position[] |
Required |
| selectedId | string \| null |
null |
| onSelect | (position: Position) => void |
— |
| onCreate | (title: string) => void |
— |
Behavior:
1. User types → filter existing positions (debounced 200ms)
2. Matching positions shown in dropdown
3. If no match: show "{typed} — Ajouter comme nouveau poste" option
4. On create: triggers onCreate callback + adds to dropdown for future use
19.6 PriceSummaryBar (Sticky)¶
Purpose: Sticky bottom bar showing selection summary during module selection.
| Prop | Type | Default |
|---|---|---|
| moduleCount | number |
Required |
| totalPrice | number |
Required |
| packName | string \| null |
null |
| packPrice | number \| null |
null |
| discountPercent | number \| null |
null |
| onContinue | () => void |
— |
Layout: Sticky to bottom, elevated (--shadow-lg), contains summary text + CTA button.
19.7 PaymentMethodSelector¶
Purpose: Radio-card selection for payment methods.
| Prop | Type | Default |
|---|---|---|
| methods | PaymentMethod[] |
Required |
| selected | string \| null |
null |
| onSelect | (method: string) => void |
— |
| amount | number |
Required |
Each method is a card with: icon, title, subtitle, action button. Cards are radio-exclusive (select one).
19.8 ConflictResolver¶
Purpose: Displays side-by-side comparison for sync conflicts.
| Prop | Type | Default |
|---|---|---|
| entityName | string |
Required |
| localVersion | Record<string, any> |
Required |
| serverVersion | Record<string, any> |
Required |
| localTimestamp | string |
Required |
| serverTimestamp | string |
Required |
| serverAuthor | string |
Required |
| onKeepLocal | () => void |
— |
| onKeepServer | () => void |
— |
Layout: Two panels (stacked on mobile, side-by-side on desktop) showing differing fields highlighted.
20. Brand Compliance Checklist¶
Papillon HR Suite (Tenant-Facing Screens)¶
- [x] Amber/gold primary color (
#F59E0B) used throughout - [x] Mobile-first layout (360px designed first, all wireframes start mobile)
- [x] Offline states specified for ALL write operations (Employee create, Org structure add, Position add)
- [x] Touch targets 48px minimum (all buttons, checkboxes, nav items)
- [x] French micro-copy warm and human ("Créez votre compte en 5 minutes", "Numéro en attente", "Tapez un nouveau poste…")
- [x] Loading skeletons specified (not spinners — except payment processing)
- [x] Generous whitespace — not crowded (single-column mobile forms, 16px padding)
- [x] Celebration animation specified: welcome confetti on first login (from host shell), "✓" animations on employee create
- [x] Auto-save on every field change (company settings, employee form draft)
- [x] Undo for destructive actions (module deactivation: 10s undo toast)
- [x] Sync status indicator specified (green/orange/blue/grey dots, "Dernière sync" timestamp)
- [x] Error messages human-readable in French (never technical codes)
- [x] Empty states with helpful illustrations and CTAs
- [x] Progressive disclosure (escape hatch for positions, optional RCCM, hire date future = PRE_HIRE explained inline)
Admin Console (ALTARYS Operators)¶
- [x] Navy/corporate color palette used (
#1E3A5Fprimary,#2563EBaccent) - [x] Desktop-only layout (1024px+ designed, no mobile wireframes)
- [x] Information density appropriate for power users (data tables, KPI cards above fold)
- [x] Batch operation flows specified (manual payment confirmation per-tenant)
- [x] Keyboard shortcuts: not specified for MVP (V2 — admin console is low-frequency)
- [x] Advanced filter/sort panels included (tenant list: status, segment, channel, date filters)
- [x] Export to CSV specified (tenant list export button)
- [x] Unverified data highlighted (orange background for is_verified=false rates)
End of document. This design covers all tenant-facing and operator-facing UI surfaces of the Control Plane module. Next steps: ARCHITECT produces
docs/architecture/control-plane-arch.md, then PRODUCT_OWNER decomposes into stories.