# Cahier des Charges — Refonte UX/Logique Office Translator

**Date :** 2026-05-02
**Auteur :** Mary (Business Analyst)
**Statut :** En attente de validation

---

## Contexte

L'application Office Translator est un SaaS de traduction de documents (DOCX, XLSX, PPTX) avec un système de plans (Free, Starter, Pro, Business, Enterprise). Plusieurs incohérences UX ont ete identifiees entre la logique business attendue et l'implementation actuelle.

**Stack technique :** Next.js 16 + React 19 + Tailwind CSS (frontend), FastAPI + Python (backend), JWT (auth).

---

## Changements requis

### 1. Retirer « Services » de la sidebar utilisateur

**Probleme :** L'entree « Services » (icone Zap) dans `DashboardSidebar` mene a `/dashboard/services`, une page qui affiche la liste des providers backend (Google, DeepL, OpenAI, etc.) avec des badges « Available ». L'utilisateur basique n'a aucune action a y faire — c'est une page d'information infrastructure.

**Fichiers concernes :**
- `frontend/src/app/dashboard/constants.ts` — retirer l'entree Services de `baseNavItems`
- `frontend/src/app/dashboard/services/page.tsx` — deplacer vers `/admin/` ou garder uniquement accessible via URL directe pour les utilisateurs avances
- `frontend/src/app/dashboard/settings/page.tsx` — retirer le lien « Translation Services » dans la carte de settings

**Regles :**
- L'entree « Services » doit etre supprimee de `baseNavItems` (ligne 15 de `constants.ts`)
- La page `/dashboard/services` peut rester accessible par URL mais ne doit plus apparaitre dans la navigation
- Dans la page Settings, la carte « Translation Services » (lignes 66-83 de `settings/page.tsx`) doit etre supprimee
- Le lien dans le dropdown mobile (si existant) doit aussi etre retire

**Impact backend :** Aucun. Les endpoints `/api/v1/providers/available` restent disponibles.

---

### 2. Refonte de la page Profil

**Probleme :** La page Profil (`profile/page.tsx`, 497 lignes) empile 6 sections heterogenes sans hierarchie visuelle claire. L'information est difficile a parcourir.

**Structure actuelle :**
- Carte identite (nom, email, date, plan)
- Carte abonnement (plan, prix, statut, renouvellement, portail Stripe)
- Zone danger (annulation)
- Carte utilisation (documents/pages avec barres de progression)
- Features incluses (liste texte)
- Preferences (langue UI : FR/EN uniquement)

**Nouvelle structure proposee — 3 onglets :**

#### Onglet 1 : « Mon Compte »
- Avatar avec initiales + nom + email (en lecture seule)
- Badge du plan actuel
- Membre depuis (date)
- Bouton « Modifier mon profil » (nom, email) — futur

#### Onglet 2 : « Abonnement »
- Plan actuel avec prix
- Statut de l'abonnement (Actif / Annulation en cours)
- Date de renouvellement ou date de fin
- Barres d'utilisation (documents/pages) avec reset date
- Credits supplementaires (si > 0)
- Bouton « Gerer la facturation » (portail Stripe)
- Bouton « Changer de forfait »
- Zone danger : annulation (avec confirmation, inchangee)
- Features incluses dans le plan

#### Onglet 3 : « Preferences »
- Langue de l'interface (voir section 3)
- Langue cible par defaut pour les traductions
- Theme (clair/sombre) — actuellement dans la sidebar, deplacer ici
- Autres preferences futures

**Fichiers concernes :**
- `frontend/src/app/dashboard/profile/page.tsx` — refonte complete
- Creer `frontend/src/app/dashboard/profile/components/` pour les sous-composants des onglets
- `frontend/src/app/dashboard/DashboardSidebar.tsx` — retirer le ThemeToggle de la sidebar (deplacer dans Preferences)

**Regles de design :**
- Utiliser le composant `Tabs` de Radix UI (deja disponible via shadcn/ui)
- Chaque onglet doit avoir une icone et un titre clair
- La zone danger (annulation) doit etre visuellement isolee, en bas de l'onglet Abonnement
- Le contenu doit respecter le systeme i18n (pas de texte hardcode)
- Responsive : les onglets se transforment en scroll horizontal sur mobile

---

### 3. Systeme de langues — Detection automatique + extension

#### 3a. Detection automatique de la langue du navigateur

**Probleme :** Dans `i18n.tsx:235`, la locale par defaut est hardcodee a `"fr"`. Aucune detection de `navigator.language`.

**Implementation :**
- Au premier chargement (pas de locale sauvegardee dans localStorage), lire `navigator.language` ou `navigator.languages[0]`
- Mapper le code retourne (ex: `fr-FR`, `en-US`, `de-DE`) vers la locale la plus proche disponible
- Logique de mapping : d'abord match exact, puis prefix (ex: `fr-FR` → `fr`, `zh-CN` → `zh`)
- Sauvegarder le resultat dans localStorage pour les visites suivantes
- Si aucune correspondance, fallback sur `"en"` (anglais comme langue par defaut internationale)

**Fichier concerne :** `frontend/src/lib/i18n.tsx`

**Code de reference pour la detection :**
```typescript
function detectBrowserLocale(): Locale {
  const browserLang = navigator.language || (navigator.languages?.[0] ?? '');
  const prefix = browserLang.split('-')[0].toLowerCase();

  // Match exact d'abord
  if (SUPPORTED_LOCALES.includes(prefix as Locale)) {
    return prefix as Locale;
  }

  // Fallback anglais
  return 'en';
}
```

#### 3b. Ajout de langues pour l'interface (UI)

**Probleme :** Le type `Locale` est limite a `"fr" | "en"` et le systeme de messages est inline dans `i18n.tsx`.

**Nouvelles locales a ajouter :**

| Code | Langue | Priorite |
|------|--------|----------|
| `de` | Deutsch | P1 |
| `es` | Espanol | P1 |
| `it` | Italiano | P1 |
| `pt` | Portugues | P1 |
| `nl` | Nederlands | P1 |
| `ru` | Русский | P1 |
| `pl` | Polski | P2 |
| `sv` | Svenska | P2 |
| `ro` | Romana | P2 |
| `el` | Ελληνικα | P2 |
| `cs` | Cestina | P2 |
| `hu` | Magyar | P2 |
| `uk` | Украiнська | P2 |
| `da` | Dansk | P3 |
| `fi` | Suomi | P3 |
| `no` | Norsk | P3 |
| `zh` | 中文 | P1 |
| `ja` | 日本語 | P1 |
| `ko` | 한국어 | P1 |
| `fa` | فارسی | P1 |

**Architecture i18n :**
1. Transformer le systeme inline en fichiers separess :
   - `frontend/src/messages/en.json` (existant, a completer)
   - `frontend/src/messages/fr.json` (existant, a completer)
   - `frontend/src/messages/de.json` (nouveau)
   - `frontend/src/messages/es.json` (nouveau)
   - etc.
2. Charger les messages dynamiquement (lazy loading) pour ne pas penaliser le bundle
3. Le type `Locale` doit etre genere dynamiquement ou etendu

**Fichiers concernes :**
- `frontend/src/lib/i18n.tsx` — refonte du systeme
- `frontend/src/messages/*.json` — un fichier par langue
- `frontend/src/app/dashboard/profile/page.tsx` — `UI_LANGUAGES` a etendre

**Contrainte RTL :** Le persan (`fa`) est une langue droite-gauche (RTL). L'application doit :
- Ajouter `dir="rtl"` sur `<html>` quand la locale est `fa` ou `ar`
- Verifier que les composants Radix UI / Tailwind supportent le RTL (utilitaires `rtl:` de Tailwind)
- Tester specifiquement les pages critiques en RTL (Translate, Profile, Settings)

#### 3c. Ajout du persan dans les langues cibles de traduction

**Probleme :** Dans `frontend/src/lib/api.ts` (lignes 22-51), le persan (`fa`) est absent de la liste `languages`, alors que le backend le supporte deja dans `middleware/validation.py` (ligne 396).

**Correction :** Ajouter `{ code: "fa", name: "فارسی", flag: "🇮🇷" }` dans le tableau `languages` de `api.ts`.

**Note :** La liste fallback dans `useTranslationConfig.ts` (ligne 38) inclut deja `fa` — seul le fichier `api.ts` est a corriger.

---

### 4. Automatisation du choix du provider de traduction

**Probleme :** Sur la page Translate, l'utilisateur doit manuellement choisir un provider (Google Traduction, DeepL, OpenAI, etc.) via le composant `ProviderSelector`. Pour un utilisateur basique, c'est une decision technique qu'il n'est pas qualifie pour prendre. Le backend a deja un systeme de fallback automatique.

**Comportement actuel :**
- `ProviderSelector.tsx` affiche tous les providers disponibles
- `TranslationModeToggle.tsx` propose un toggle Classic/LLM
- `useTranslationConfig.ts` exige un provider selectionne pour valider la config (`isConfigValid` ligne 184-188)
- Les providers LLM sont deja bloques pour les non-Pro

**Nouveau comportement propose :**

#### Pour les utilisateurs Free / Starter :
- Le `ProviderSelector` et le `TranslationModeToggle` sont **completement caches**
- Le provider est automatiquement selectionne : premier provider classic disponible
- Si aucun provider classic n'est disponible, utiliser le premier provider de la liste
- L'utilisateur ne voit que : fichier → langue source → langue cible → Traduire

#### Pour les utilisateurs Pro / Business / Enterprise :
- Afficher un selecteur simplifie, pas technique :
  - Remplacer les noms techniques par des labels utilisateur :
    - « Traduction rapide » (classic) au lieu de « Google Traduction »
    - « Traduction intelligente » (LLM) au lieu de « OpenAI GPT-4 »
  - Pas de toggle Classic/LLM separe — juste un selecteur de mode avec descriptions claires
  - Les providers LLM sont accessibles sans cadenas (deja Pro)

#### Implementation technique :

**Fichiers concernes :**
- `frontend/src/app/dashboard/translate/ProviderSelector.tsx` — cacher pour Free/Starter, simplifier pour Pro+
- `frontend/src/app/dashboard/translate/TranslationModeToggle.tsx` — retirer, fusionner dans ProviderSelector simplifie
- `frontend/src/app/dashboard/translate/useTranslationConfig.ts` — auto-selection du provider pour les utilisateurs basiques
- `frontend/src/app/dashboard/translate/page.tsx` — adapter le layout selon le tier

**Logique d'auto-selection (dans `useTranslationConfig.ts`) :**
```typescript
// Apres le fetch des providers disponibles
if (!isPro && availableProviders.length > 0) {
  // Auto-selectionner le premier provider classic
  const classicProvider = availableProviders.find(p => p.mode === 'classic');
  const fallback = availableProviders[0];
  setProvider((classicProvider ?? fallback).id);
}
```

**Mise a jour de `isConfigValid` :**
```typescript
// Pour les non-Pro, le provider est auto-selectionne
// Donc isConfigValid ne depend plus de la selection manuelle
const isConfigValid = useMemo(() => {
  if (!hasFile || !targetLang) return false;
  if (isPro && !provider) return false; // Pro doit choisir
  return true; // Non-Pro : auto-selectionne
}, [hasFile, targetLang, isPro, provider]);
```

**Nouveau composant simplifie pour Pro (remplace ProviderSelector + ModeToggle) :**
```typescript
// SimplifiedProviderSelector — uniquement pour Pro+
// Affiche :
// - "Traduction rapide" — Traduction automatique rapide (130+ langues)
// - "Traduction intelligente" — Traduction contextuelle par IA (Pro)
```

---

## Plan d'implementation par ordre de priorite

### Phase 1 — Quick Wins (impact eleve, complexite faible)
1. Retirer « Services » de la sidebar et de la page Settings
2. Ajouter `fa` (persan) dans `api.ts`
3. Auto-selection du provider pour les utilisateurs Free/Starter
4. Detection automatique de la langue du navigateur

### Phase 2 — Refonte Profil (impact eleve, complexite moyenne)
5. Refactorer la page Profil en 3 onglets
6. Deplacer ThemeToggle dans l'onglet Preferences
7. i18n-ifier tous les textes hardcodes du profil

### Phase 3 — Extension i18n (impact eleve, complexite elevee)
8. Refondre le systeme i18n en fichiers separes
9. Ajouter les langues P1 (de, es, it, pt, nl, ru, zh, ja, ko, fa)
10. Support RTL pour `fa` et `ar`
11. Ajouter les langues P2 et P3 progressivement

---

## Risques et mitigations

| Risque | Probabilite | Impact | Mitigation |
|--------|-------------|--------|------------|
| Traductions i18n de mauvaise qualite | Elevee | Moyen | Utiliser un service de traduction professionnel ou validation humaine pour les langues principales |
| Layout casse en RTL | Moyen | Eleve | Tester avec `fa` et `ar` des le debut, ajouter les utilitaires Tailwind `rtl:` |
| Utilisateurs Pro perdus sans selecteur technique | Faible | Faible | Garder le selecteur simplifie avec option avancee |
| Performance avec 20+ fichiers de langue | Faible | Faible | Lazy loading des fichiers JSON par locale |

---

## Critères d'acceptation

- [ ] Aucune entree « Services » visible dans la sidebar utilisateur
- [ ] La page Profil est separee en 3 onglets fonctionnels
- [ ] La langue de l'interface est detectee automatiquement depuis le navigateur
- [ ] Le persan est disponible comme langue cible de traduction
- [ ] Le persan est disponible comme langue de l'interface (avec support RTL)
- [ ] L'utilisateur Free/Starter ne voit aucun selecteur de provider
- [ ] L'utilisateur Pro voit un selecteur simplifie (non-technique)
- [ ] Toutes les nouvelles langues UI ont des fichiers de messages complets
- [ ] Le theme clair/sombre est accessible depuis l'onglet Preferences du profil
