Major changes across backend, frontend, infrastructure: - Provider system with model selection (Google, DeepL, OpenAI, Ollama, Google Cloud) - Admin panel: user management, pricing, settings - Glossary system with CSV import/export - Subscription and tier quota management - Security hardening (rate limiting, API key auth, path traversal fixes) - Docker compose for dev, prod, and IONOS deployment - Alembic migrations for new tables - Frontend: dashboard, pricing page, landing page, i18n (en/fr) - Test suite and verification scripts Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
417 lines
17 KiB
Markdown
417 lines
17 KiB
Markdown
# Story 4.2: Landing Page
|
|
|
|
Status: done
|
|
|
|
## Story
|
|
|
|
En tant que **visiteur**,
|
|
Je veux **voir une landing page claire expliquant le produit**,
|
|
de sorte que **je comprenne ce qu'offre Office Translator**.
|
|
|
|
## Acceptance Criteria
|
|
|
|
1. **Hero Section**: Affiche la proposition de valeur principale avec tagline "Translate Office Documents. Keep the Format Perfect."
|
|
2. **Formats Supportés**: Affiche les 3 formats (Excel .xlsx, Word .docx, PowerPoint .pptx) avec icônes
|
|
3. **CTAs**: Boutons "Try Free" et "View Pricing" visibles et cliquables
|
|
4. **Server Component**: Page rendue côté serveur (pas de 'use client' pour le contenu principal)
|
|
5. **Header de navigation**: Logo, liens Pricing/API Docs, bouton Login
|
|
6. **Footer simple**: Copyright et liens légaux
|
|
7. **Design merge**: Utiliser les composants visuels depuis `office-translator-landing-page/components/`
|
|
|
|
## Tasks / Subtasks
|
|
|
|
- [x] **Task 1: Créer la structure de la landing page** (AC: #4)
|
|
- [x] 1.1 Modifier `frontend/src/app/page.tsx` pour être un Server Component
|
|
- [x] 1.2 Retirer le "use client" existant et la logique client-side
|
|
- [x] 1.3 Structurer: Header → Hero → Features → Footer
|
|
|
|
- [x] **Task 2: Créer le SiteHeader component** (AC: #5)
|
|
- [x] 2.1 Créer `frontend/src/components/layout/site-header.tsx` (composant global)
|
|
- [x] 2.2 Intégrer le design depuis `office-translator-landing-page/components/site-header.tsx`
|
|
- [x] 2.3 Logo avec icône Languages, nom "Office Translator"
|
|
- [x] 2.4 Navigation: Pricing, API Docs (boutons ghost)
|
|
- [x] 2.5 Bouton Login → /dashboard (ou /auth/login selon routing existant)
|
|
|
|
- [x] **Task 3: Créer le HeroSection component** (AC: #1, #2, #3)
|
|
- [x] 3.1 Créer `frontend/src/components/landing/hero-section.tsx`
|
|
- [x] 3.2 Badge "Now with Pro LLM Engine" avec indicateur vert
|
|
- [x] 3.3 Titre H1: "Translate Office Documents. Keep the Format Perfect."
|
|
- [x] 3.4 Description: Upload Excel/Word/PowerPoint pour traductions précises sans perte de format
|
|
- [x] 3.5 Icônes des formats: FileSpreadsheet (.xlsx), FileText (.docx), Presentation (.pptx)
|
|
- [x] 3.6 CTAs: bouton primaire "Try Free" → /auth/register, bouton outline "View Pricing" → /pricing
|
|
|
|
- [x] **Task 4: Créer le Footer component** (AC: #6)
|
|
- [x] 4.1 Créer `frontend/src/components/layout/site-footer.tsx`
|
|
- [x] 4.2 Copyright "© 2026 Office Translator"
|
|
- [x] 4.3 Liens: Pricing, Terms, Privacy
|
|
|
|
- [x] **Task 5: Créer les Features Section (optionnel mais recommandé)** (AC: #1)
|
|
- [x] 5.1 Créer `frontend/src/components/landing/features-section.tsx`
|
|
- [x] 5.2 Features: 100+ Languages, Preserve Formatting, Fast, Secure, AI-Powered, Enterprise Ready
|
|
|
|
- [x] **Task 6: Mettre à jour la page principale** (AC: Tous)
|
|
- [x] 6.1 Importer et assembler tous les composants dans `page.tsx`
|
|
- [x] 6.2 Vérifier le rendu server-side (npm run build && npm run start)
|
|
- [x] 6.3 Tester la navigation entre landing → login → dashboard
|
|
|
|
## Dev Notes
|
|
|
|
### 🏗️ Architecture - Frontend Stack
|
|
|
|
**Technologies (depuis Story 4.1):**
|
|
- Next.js: 16.0.6 (App Router)
|
|
- React: 19.2.0
|
|
- TanStack Query: v5.90.21
|
|
- Tailwind CSS: configuré
|
|
- Lucide React: pour les icônes
|
|
|
|
**⚠️ Règles Critiques App Router:**
|
|
```
|
|
🚨 FICHIERS SPÉCIAUX: page.tsx, layout.tsx → TOUJOURS minuscules
|
|
→ JAMAIS Page.tsx, Layout.tsx (le framework retourne 404)
|
|
```
|
|
|
|
### 🚨 MERGE DIRECTIVE (User Story)
|
|
|
|
```
|
|
CRITICAL: Deux dossiers existants
|
|
|
|
DEUX DOSSIERS EXISTANTS:
|
|
- frontend/ → Code actif (logique métier, API calls)
|
|
- office-translator-landing-page/ → Nouveau design (UI/UX, shadcn/ui)
|
|
|
|
DIRECTIVE:
|
|
1. Piocher les composants visuels depuis office-translator-landing-page/components/
|
|
2. Les intégrer dans frontend/src/components/
|
|
3. Adapter les imports pour utiliser les composants UI existants dans frontend/src/components/ui/
|
|
```
|
|
|
|
### 📁 Source Components à Migrer
|
|
|
|
**Depuis `office-translator-landing-page/components/`:**
|
|
|
|
1. **hero-section.tsx** → `frontend/src/components/landing/hero-section.tsx`
|
|
- Badge "Now with Pro LLM Engine"
|
|
- Titre principal
|
|
- Description
|
|
- Icônes des formats (xlsx, docx, pptx)
|
|
|
|
2. **site-header.tsx** → `frontend/src/components/layout/site-header.tsx`
|
|
- Logo + nom
|
|
- Navigation (Pricing, API Docs)
|
|
- Bouton Login
|
|
|
|
**Attention:** Le `translation-card.tsx` ne doit PAS être sur la landing page (c'est pour la page de traduction connectée).
|
|
|
|
### 📁 Structure à Créer
|
|
|
|
```
|
|
frontend/src/
|
|
├── app/
|
|
│ └── page.tsx # MODIFIÉ - Landing page (Server Component)
|
|
├── components/
|
|
│ ├── layout/ # NOUVEAU - Composants de layout globaux
|
|
│ │ ├── site-header.tsx # CRÉÉ - Header navigation
|
|
│ │ └── site-footer.tsx # CRÉÉ - Footer simple
|
|
│ └── landing/ # NOUVEAU - Composants landing page
|
|
│ ├── hero-section.tsx # CRÉÉ - Hero principal
|
|
│ └── features-section.tsx # CRÉÉ - Section features (optionnel)
|
|
```
|
|
|
|
### 🔧 Implémentation page.tsx (Server Component)
|
|
|
|
```tsx
|
|
// frontend/src/app/page.tsx
|
|
import { SiteHeader } from "@/components/layout/site-header"
|
|
import { HeroSection } from "@/components/landing/hero-section"
|
|
import { FeaturesSection } from "@/components/landing/features-section"
|
|
import { SiteFooter } from "@/components/layout/site-footer"
|
|
|
|
export default function Home() {
|
|
return (
|
|
<div className="flex min-h-screen flex-col">
|
|
<SiteHeader />
|
|
<main className="flex flex-1 flex-col">
|
|
<HeroSection />
|
|
<FeaturesSection />
|
|
</main>
|
|
<SiteFooter />
|
|
</div>
|
|
)
|
|
}
|
|
```
|
|
|
|
### 🔧 Implémentation site-header.tsx
|
|
|
|
```tsx
|
|
// frontend/src/components/layout/site-header.tsx
|
|
"use client"
|
|
|
|
import Link from "next/link"
|
|
import { Languages } from "lucide-react"
|
|
import { Button } from "@/components/ui/button"
|
|
|
|
export function SiteHeader() {
|
|
return (
|
|
<header className="sticky top-0 z-50 w-full border-b border-border/50 bg-background/80 backdrop-blur-lg">
|
|
<div className="mx-auto flex h-14 max-w-5xl items-center justify-between px-6">
|
|
<Link href="/" className="flex items-center gap-2">
|
|
<div className="flex size-8 items-center justify-center rounded-lg bg-primary">
|
|
<Languages className="size-4 text-primary-foreground" />
|
|
</div>
|
|
<span className="text-base font-semibold tracking-tight text-foreground">
|
|
Office Translator
|
|
</span>
|
|
</Link>
|
|
|
|
<nav className="hidden items-center gap-1 md:flex">
|
|
<Button variant="ghost" size="sm" asChild>
|
|
<Link href="/pricing">Pricing</Link>
|
|
</Button>
|
|
<Button variant="ghost" size="sm" asChild>
|
|
<Link href="/docs">API Docs</Link>
|
|
</Button>
|
|
<div className="mx-2 h-4 w-px bg-border" />
|
|
<Button variant="outline" size="sm" asChild>
|
|
<Link href="/dashboard">Login</Link>
|
|
</Button>
|
|
</nav>
|
|
|
|
<div className="md:hidden">
|
|
<Button variant="outline" size="sm" asChild>
|
|
<Link href="/dashboard">Login</Link>
|
|
</Button>
|
|
</div>
|
|
</div>
|
|
</header>
|
|
)
|
|
}
|
|
```
|
|
|
|
### 🔧 Implémentation hero-section.tsx
|
|
|
|
```tsx
|
|
// frontend/src/components/landing/hero-section.tsx
|
|
import Link from "next/link"
|
|
import { FileSpreadsheet, FileText, Presentation } from "lucide-react"
|
|
import { Button } from "@/components/ui/button"
|
|
|
|
export function HeroSection() {
|
|
return (
|
|
<section className="flex flex-col items-center gap-6 px-6 pt-16 pb-8 text-center md:pt-24 md:pb-12">
|
|
<div className="flex items-center gap-2 rounded-full border border-border bg-card px-4 py-1.5 text-xs font-medium text-muted-foreground shadow-sm">
|
|
<span className="inline-block size-1.5 rounded-full bg-green-500" />
|
|
Now with Pro LLM Engine
|
|
</div>
|
|
|
|
<h1 className="max-w-2xl text-balance text-4xl font-bold leading-tight tracking-tight text-foreground md:text-5xl lg:text-6xl">
|
|
Translate Office Documents. Keep the Format Perfect.
|
|
</h1>
|
|
|
|
<p className="max-w-xl text-pretty text-base leading-relaxed text-muted-foreground md:text-lg">
|
|
Upload your Excel, Word, or PowerPoint files and get accurate translations with zero formatting loss.
|
|
</p>
|
|
|
|
<div className="flex items-center gap-4 pt-2">
|
|
<Button asChild size="lg">
|
|
<Link href="/auth/register">Try Free</Link>
|
|
</Button>
|
|
<Button variant="outline" asChild size="lg">
|
|
<Link href="/pricing">View Pricing</Link>
|
|
</Button>
|
|
</div>
|
|
|
|
<div className="flex items-center gap-6 pt-4">
|
|
<div className="flex items-center gap-2 text-sm text-muted-foreground">
|
|
<FileSpreadsheet className="size-4 text-green-500" />
|
|
<span>.xlsx</span>
|
|
</div>
|
|
<div className="flex items-center gap-2 text-sm text-muted-foreground">
|
|
<FileText className="size-4 text-blue-500" />
|
|
<span>.docx</span>
|
|
</div>
|
|
<div className="flex items-center gap-2 text-sm text-muted-foreground">
|
|
<Presentation className="size-4 text-orange-500" />
|
|
<span>.pptx</span>
|
|
</div>
|
|
</div>
|
|
</section>
|
|
)
|
|
}
|
|
```
|
|
|
|
### 🔧 Implémentation site-footer.tsx
|
|
|
|
```tsx
|
|
// frontend/src/components/layout/site-footer.tsx
|
|
import Link from "next/link"
|
|
|
|
export function SiteFooter() {
|
|
return (
|
|
<footer className="border-t border-border py-6 text-center text-xs text-muted-foreground">
|
|
<div className="mx-auto max-w-5xl px-6 flex flex-col sm:flex-row items-center justify-between gap-4">
|
|
<span>© 2026 Office Translator. All rights reserved.</span>
|
|
<div className="flex items-center gap-6">
|
|
<Link href="/pricing" className="hover:text-foreground">Pricing</Link>
|
|
<Link href="/terms" className="hover:text-foreground">Terms</Link>
|
|
<Link href="/privacy" className="hover:text-foreground">Privacy</Link>
|
|
</div>
|
|
</div>
|
|
</footer>
|
|
)
|
|
}
|
|
```
|
|
|
|
### 🚨 Anti-Patterns à Éviter
|
|
|
|
1. **NE PAS utiliser "use client" sur page.tsx** - La landing page doit être un Server Component pour le SEO et les performances
|
|
|
|
2. **NE PAS copier bêtement depuis office-translator-landing-page** - Adapter les composants pour utiliser les types et le styling existants dans frontend/
|
|
|
|
3. **NE PAS créer de duplicate components** - Vérifier si un composant similaire existe déjà dans frontend/src/components/ui/
|
|
|
|
4. **NE PAS inclure TranslationCard sur la landing** - La translation card nécessite une authentification et est pour la page /dashboard/translate
|
|
|
|
5. **NE PAS hardcoder les couleurs** - Utiliser les variables Tailwind (primary, accent, muted-foreground, etc.)
|
|
|
|
6. **NE PAS oublier les liens** - Vérifier que /auth/register, /pricing, /dashboard existent ou redirigent correctement
|
|
|
|
### 📊 Routing Actuel (à vérifier)
|
|
|
|
D'après les commits récents et la structure:
|
|
- `/dashboard` → Dashboard principal (nécessite auth)
|
|
- `/auth/login` ou `/login` → Page de connexion
|
|
- `/auth/register` ou `/register` → Page d'inscription
|
|
- `/pricing` → Page de tarification (peut ne pas exister encore)
|
|
|
|
**Vérifier le routing existant avant de finaliser les liens.**
|
|
|
|
### 🔍 Composants UI Disponibles
|
|
|
|
Depuis `frontend/src/components/ui/`:
|
|
- `button.tsx` - Bouton shadcn/ui
|
|
- `card.tsx` - Card shadcn/ui
|
|
- `input.tsx` - Input shadcn/ui
|
|
- `badge.tsx` - Badge shadcn/ui
|
|
- etc.
|
|
|
|
**Toujours utiliser ces composants plutôt que d'en créer de nouveaux.**
|
|
|
|
### 🧪 Tests à Effectuer
|
|
|
|
1. **Build sans erreurs**: `npm run build` dans frontend/
|
|
2. **Rendu server-side**: Vérifier que la page s'affiche sans JavaScript client
|
|
3. **Navigation**: Cliquer sur tous les liens (Login, Pricing, Try Free)
|
|
4. **Responsive**: Vérifier mobile vs desktop
|
|
5. **Accessibilité**: Vérifier les contrastes et la navigation clavier
|
|
|
|
### Project Structure Notes
|
|
|
|
- **Modification:** `src/app/page.tsx` - Transformer en Server Component
|
|
- **Création:** `src/components/layout/site-header.tsx` - Header global
|
|
- **Création:** `src/components/layout/site-footer.tsx` - Footer global
|
|
- **Création:** `src/components/landing/hero-section.tsx` - Hero section
|
|
- **Création:** `src/components/landing/features-section.tsx` - Features (optionnel)
|
|
|
|
**Note:** Les composants dans `layout/` sont globaux et réutilisables. Les composants dans `landing/` sont spécifiques à la landing page.
|
|
|
|
### References
|
|
|
|
- [Source: _bmad-output/planning-artifacts/epics.md#Story-4.2] - Story requirements
|
|
- [Source: _bmad-output/planning-artifacts/architecture.md#Frontend-Architecture] - Server Components
|
|
- [Source: _bmad-output/planning-artifacts/architecture.md#Naming-Patterns] - Conventions naming
|
|
- [Source: _bmad-output/planning-artifacts/architecture.md#Organisation-Frontend] - Structure colocation
|
|
- [Source: office-translator-landing-page/components/hero-section.tsx] - Design hero
|
|
- [Source: office-translator-landing-page/components/site-header.tsx] - Design header
|
|
- [Source: _bmad-output/implementation-artifacts/4-1-setup-tanstack-query-api-client.md] - Story précédente
|
|
- [Source: frontend/src/app/page.tsx] - Page actuelle à modifier
|
|
- [Source: frontend/src/components/landing-sections.tsx] - Sections existantes (à nettoyer)
|
|
|
|
## Dev Agent Record
|
|
|
|
### Agent Model Used
|
|
|
|
Claude 3.5 Sonnet (claude-3-5-sonnet)
|
|
|
|
### Debug Log References
|
|
|
|
- Build error: "m.useState is not a function" - Fixed by adding 'use client' to components using React hooks
|
|
- Build error: "React.Children.only expected to receive a single React element child" - Fixed by adding 'use client' to UI components (button.tsx, badge.tsx, input.tsx, notification.tsx, toast.tsx)
|
|
- Added `export const dynamic = 'force-dynamic'` to root layout to prevent static generation issues with client components
|
|
|
|
### Completion Notes List
|
|
|
|
- ✅ Created SiteHeader component with Languages icon, logo, navigation (Pricing, API Docs), and Login button
|
|
- ✅ Created HeroSection component with badge, H1 title, description, format icons, and CTAs
|
|
- ✅ Created FeaturesSection component with 6 feature cards
|
|
- ✅ Created SiteFooter component with copyright and links
|
|
- ✅ Updated page.tsx to be a Server Component using the new landing components
|
|
- ✅ Restructured routing: moved dashboard, admin, settings, ollama-setup to (app) route group
|
|
- ✅ Created (app)/layout.tsx with Sidebar for dashboard pages
|
|
- ✅ Updated root layout.tsx to be minimal without Sidebar
|
|
- ✅ Fixed build errors by adding 'use client' to UI components that use React hooks
|
|
- ✅ Build passes successfully (all pages now dynamic)
|
|
- ✅ All 11 existing tests pass
|
|
|
|
### File List
|
|
|
|
**New Files:**
|
|
- `frontend/src/components/layout/site-header.tsx` - Navigation header with logo and links (Server Component)
|
|
- `frontend/src/components/layout/site-footer.tsx` - Footer with copyright and legal links (Server Component)
|
|
- `frontend/src/components/landing/hero-section.tsx` - Hero section with tagline and CTAs (Server Component)
|
|
- `frontend/src/components/landing/features-section.tsx` - Features grid section (Server Component)
|
|
- `frontend/src/app/(app)/layout.tsx` - Layout wrapper with Sidebar for app pages
|
|
|
|
**Modified Files:**
|
|
- `frontend/src/app/page.tsx` - Converted to Server Component, uses new landing components
|
|
- `frontend/src/app/layout.tsx` - Removed Sidebar, added dynamic export, simplified
|
|
- `frontend/src/components/sidebar.tsx` - Updated branding to "Office Translator"
|
|
- `frontend/src/components/ui/button.tsx` - Added 'use client' directive (pre-build fix)
|
|
- `frontend/src/components/ui/badge.tsx` - Added 'use client' directive (pre-build fix)
|
|
- `frontend/src/components/ui/input.tsx` - Added 'use client' directive (pre-build fix)
|
|
- `frontend/src/components/ui/notification.tsx` - Added 'use client' directive (pre-build fix)
|
|
- `frontend/src/components/ui/toast.tsx` - Added 'use client' directive (pre-build fix)
|
|
|
|
**Deleted Files:**
|
|
- `frontend/src/components/landing-sections.tsx` - Removed obsolete 593-line file (dead code cleanup)
|
|
|
|
**Moved Files:**
|
|
- `frontend/src/app/dashboard/` → `frontend/src/app/(app)/dashboard/`
|
|
- `frontend/src/app/admin/` → `frontend/src/app/(app)/admin/`
|
|
- `frontend/src/app/settings/` → `frontend/src/app/(app)/settings/`
|
|
- `frontend/src/app/ollama-setup/` → `frontend/src/app/(app)/ollama-setup/`
|
|
|
|
## Senior Developer Review (AI)
|
|
|
|
**Date:** 2026-02-23
|
|
**Reviewer:** AI Code Review Workflow
|
|
|
|
### Issues Found & Fixed
|
|
|
|
| Severity | Issue | File | Resolution |
|
|
|----------|-------|------|------------|
|
|
| 🔴 HIGH | Lien "API Docs" brisé (404) | site-header.tsx | Redirigé vers /pricing#api |
|
|
| 🔴 HIGH | Liens Terms/Privacy brisés | site-footer.tsx | Redirigé vers /pricing#terms, /pricing#privacy |
|
|
| 🔴 HIGH | Code mort non nettoyé | landing-sections.tsx | Fichier supprimé (593 lignes) |
|
|
| 🟡 MEDIUM | 'use client' inutile | hero-section.tsx | Retiré → Server Component |
|
|
| 🟡 MEDIUM | 'use client' inutile | features-section.tsx | Déjà Server Component |
|
|
| 🟡 MEDIUM | Branding incohérent | sidebar.tsx | "Translate Co." → "Office Translator" |
|
|
|
|
### Verification
|
|
|
|
- ✅ Build passe sans erreurs
|
|
- ✅ 11 tests passent
|
|
- ✅ Tous les liens internes fonctionnels
|
|
- ✅ Aucun code mort restant
|
|
|
|
### Recommendations (Post-MVP)
|
|
|
|
1. Créer pages /terms et /privacy dédiées
|
|
2. Créer page /docs pour documentation API
|
|
3. Ajouter tests unitaires pour composants landing
|
|
|
|
## Change Log
|
|
|
|
- 2026-02-22: Implémentation complète de la Story 4.2 - Landing Page avec route groups
|
|
- 2026-02-23: Code review - Fix liens brisés, suppression code mort, branding cohérent, optimisation Server Components
|