npm package: @lastbrain/module-tools
Description: ## 🎯 Principe
Latest version: 0.1.3

# Module Tools - Architecture automatique "1 outil = 1 dossier"

## 🎯 Principe

**Pour ajouter un outil : copiez un dossier, modifiez-le et ajoutez 1 ligne dans le registry.**

Chaque outil est 100% isolé dans son propre dossier avec :

- ✅ Traductions UI (fr/en/es)
- ✅ Contenu SEO complet (fr/en/es)
- ✅ Composant React (client ou server)
- ✅ Métadonnées (catégorie, statut, ordre)

L'outil sera **automatiquement** listé et accessible sur `/tools` et `/tools/[slug]`.

## 📁 Structure du projet

```
packages/module-tools/src/
├── tools.build.config.ts        # Configuration module (routes, menu)
├── index.ts                     # Exports publics
├── server.ts                    # Exports server-side
└── web/
    └── public/
        ├── HomePage.tsx         # HomePage client
        ├── HomePageServer.tsx   # HomePage server avec metadata
        └── tools/
            ├── _registry/
            │   ├── types.ts                    # Types TypeScript
            │   └── tools.registry.ts           # ⚙️ REGISTRY - Liste des outils
            ├── _components/
            │   ├── ToolCard.tsx                # Carte outil (grille)
            │   ├── ToolsGrid.tsx               # Grille responsive
            │   ├── ToolLayoutDesktop.tsx       # Layout desktop (aside + SEO)
            │   └── ToolLayoutMobile.tsx        # Layout mobile (accordéons)
            ├── page.tsx                        # 📄 /tools (liste)
            ├── [slug]/
            │   └── page.tsx                    # 📄 /tools/[slug] (détail)
            │
            ├── png-to-webp/                    # ✅ OUTIL 1 (interactif)
            │   ├── i18n.ts                     # Traductions UI
            │   ├── seo.ts                      # Contenu SEO (2800 lignes)
            │   ├── tool.client.tsx             # Composant "use client"
            │   └── index.ts                    # Export standardisé
            │
            └── career-timeline/                # ✅ OUTIL 2 (statique)
                ├── i18n.ts                     # Traductions UI
                ├── seo.ts                      # Contenu SEO
                ├── tool.server.tsx             # Composant serveur
                └── index.ts                    # Export standardisé
```

## ✨ Ajouter un nouvel outil (4 étapes)

### 1️⃣ Copier un dossier existant

```bash
cd packages/module-tools/src/web/public/tools/

# Pour un outil interactif (upload, conversion, etc.)
cp -r png-to-webp mon-outil

# Pour un outil statique (affichage, documentation)
cp -r career-timeline mon-outil
```

### 2️⃣ Modifier les fichiers du dossier

Vous avez 4 fichiers à éditer :

#### `index.ts` - Point d'entrée

```typescript
import { translations } from "./i18n";
import { seoContent } from "./seo";

export const TOOL_SLUG = "mon-outil"; // ⚠️ Doit correspondre au nom du dossier

export function getToolDefinition() {
  return {
    slug: TOOL_SLUG,
    category: "productivity", // image | development | design | productivity
    status: "active", // active | beta | coming-soon
    isInteractive: true, // true = client | false = server
    featured: false,
    order: 10,
    i18n: translations,
    seo: seoContent,
    relatedTools: ["png-to-webp"], // Outils suggérés
  };
}

// Choisir selon le type
export { default as ToolClient } from "./tool.client"; // Si interactif
// OU
// export { default as ToolClient } from "./tool.server"; // Si statique
```

#### `i18n.ts` - Traductions UI

```typescript
import type { ToolI18n } from "../_registry/types";

export const translations: ToolI18n = {
  fr: {
    title: "Mon Outil",
    description: "Description courte pour la card",
    labels: {
      // Labels spécifiques à votre outil
      uploadButton: "Charger un fichier",
      convert: "Convertir",
      download: "Télécharger",
    },
  },
  en: {
    title: "My Tool",
    description: "Short description for card",
    labels: {
      uploadButton: "Upload file",
      convert: "Convert",
      download: "Download",
    },
  },
  es: {
    title: "Mi Herramienta",
    description: "Descripción breve para la tarjeta",
    labels: {
      uploadButton: "Cargar archivo",
      convert: "Convertir",
      download: "Descargar",
    },
  },
};
```

#### `seo.ts` - Contenu SEO riche

```typescript
import type { ToolSEO } from "../_registry/types";

export const seoContent: ToolSEO = {
  fr: {
    title: "Mon Outil - LastBrain Tools",
    description: "Meta description optimisée (150-160 caractères)",
    h1: "Titre principal H1 pour SEO",
    keywords: ["mot-clé1", "mot-clé2", "mot-clé3"],
    sections: {
      why: {
        title: "Pourquoi utiliser cet outil ?",
        content:
          "Explication détaillée des bénéfices, cas d'usage, pourquoi c'est utile...",
      },
      useCases: {
        title: "Cas d'usage",
        items: [
          "Cas d'usage 1 : explication",
          "Cas d'usage 2 : explication",
          "Cas d'usage 3 : explication",
        ],
      },
      howTo: {
        title: "Comment l'utiliser ?",
        steps: [
          "Étape 1 : Description claire",
          "Étape 2 : Description claire",
          "Étape 3 : Description claire",
        ],
      },
      faq: [
        {
          question: "Question fréquente 1 ?",
          answer: "Réponse détaillée avec contexte...",
        },
        {
          question: "Question fréquente 2 ?",
          answer: "Réponse détaillée avec contexte...",
        },
      ],
    },
  },
  en: {
    title: "My Tool - LastBrain Tools",
    description: "Optimized meta description (150-160 chars)",
    // ... même structure en anglais
  },
  es: {
    title: "Mi Herramienta - LastBrain Tools",
    description: "Meta descripción optimizada (150-160 caracteres)",
    // ... même structure en espagnol
  },
};
```

#### `tool.client.tsx` - Composant interactif (option A)

```tsx
"use client";

import { useState } from "react";
import { Button, Card } from "@lastbrain/ui";
import type { Language } from "../_registry/types";
import { translations } from "./i18n";

interface ToolClientProps {
  lang: Language;
}

export default function MonOutilClient({ lang }: ToolClientProps) {
  const [result, setResult] = useState("");
  const t = translations[lang].labels;

  const handleAction = () => {
    // Votre logique métier ici
    setResult("Résultat de l'opération");
  };

  return (
    <Card className="p-6">
      <div className="space-y-4">
        <Button onClick={handleAction} color="primary">
          {t.uploadButton}
        </Button>

        {result && (
          <div className="p-4 bg-success-50 rounded-lg">
            <p className="text-success-700">{result}</p>
          </div>
        )}
      </div>
    </Card>
  );
}
```

#### `tool.server.tsx` - Composant statique (option B)

```tsx
import { Card } from "@lastbrain/ui";
import type { Language } from "../_registry/types";
import { translations } from "./i18n";

interface ToolServerProps {
  lang: Language;
}

export default function MonOutilServer({ lang }: ToolServerProps) {
  const t = translations[lang].labels;

  return (
    <Card className="p-6">
      <h2 className="text-xl font-bold mb-4">{translations[lang].title}</h2>
      <p className="text-default-600">{translations[lang].description}</p>

      {/* Votre contenu statique ici */}
      <div className="mt-6">
        <p>Exemple de contenu...</p>
      </div>
    </Card>
  );
}
```

### 3️⃣ Déclarer dans le registry

Ouvrir `_registry/tools.registry.ts` et ajouter **1 ligne** :

```typescript
const TOOL_MODULES = {
  "png-to-webp": () => import("../png-to-webp"),
  "career-timeline": () => import("../career-timeline"),
  "mon-outil": () => import("../mon-outil"), // ✅ Ajoutez cette ligne
} as const;
```

C'est tout ! Le reste est automatique.

### 4️⃣ Rebuild

```bash
cd apps/lastbrain
pnpm build:modules
```

Votre outil est maintenant disponible sur :

- `/tools` (dans la liste)
- `/tools/mon-outil` (page détail)

## 🏗️ Architecture technique

### Registry Pattern

Le système utilise un **registry** avec imports dynamiques :

```typescript
// _registry/tools.registry.ts
const TOOL_MODULES = {
  "png-to-webp": () => import("../png-to-webp"),
  // ... lazy loading de chaque outil
} as const;

// Détection automatique des slugs disponibles
export type ToolSlug = keyof typeof TOOL_MODULES;

// Chargement à la demande
export async function getToolDefinition(slug: string) {
  const loader = TOOL_MODULES[slug];
  const module = await loader();
  return module.getToolDefinition();
}
```

### Layouts Responsive

Deux layouts automatiques selon le device :

#### Desktop (`ToolLayoutDesktop.tsx`)

```
┌─────────────────────────────────────────┐
│ Aside (related tools)  │  Main Content  │
│                       │                 │
│ - Tool 1              │  H1 + Desc      │
│ - Tool 2              │  [Tool UI]      │
│ - Tool 3              │                 │
│                       │  SEO Sections:  │
│                       │  • Pourquoi ?   │
│                       │  • Cas d'usage  │
│                       │  • Comment ?    │
│                       │  • FAQ          │
└────────────────────────────────────────┘
```

#### Mobile (`ToolLayoutMobile.tsx`)

```
┌───────────────────┐
│ H1 + Description  │
├───────────────────┤
│ [Tool UI]         │
├───────────────────┤
│ 📖 À propos ▼     │ (Accordion)
├───────────────────┤
│ 💡 Conseils ▼     │ (Accordion)
├───────────────────┤
│ ❓ FAQ ▼          │ (Accordion)
└───────────────────┘
```

### Pages générées

#### `/tools` - Liste (page.tsx)

- Server Component
- `generateMetadata()` pour SEO
- Filtre par catégorie
- Grille de cards responsive

#### `/tools/[slug]` - Détail ([slug]/page.tsx)

- Server Component
- `generateStaticParams()` pour SSG
- `generateMetadata()` dynamique
- Layout Desktop/Mobile conditionnel

## 📊 Types TypeScript

### `ToolDefinition`

```typescript
interface ToolDefinition {
  slug: string;
  category: "image" | "development" | "design" | "productivity";
  status: "active" | "beta" | "coming-soon";
  isInteractive: boolean; // Client vs Server Component
  featured: boolean;
  order: number;
  i18n: ToolI18n;
  seo: ToolSEO;
  relatedTools?: string[];
}
```

### `ToolI18n`

```typescript
interface ToolI18n {
  fr: { title: string; description: string; labels: Record<string, string> };
  en: { title: string; description: string; labels: Record<string, string> };
  es: { title: string; description: string; labels: Record<string, string> };
}
```

### `ToolSEO`

```typescript
interface ToolSEO {
  [lang: string]: {
    title: string;
    description: string;
    h1: string;
    keywords: string[];
    sections: {
      why: { title: string; content: string };
      useCases: { title: string; items: string[] };
      howTo?: { title: string; steps: string[] };
      faq?: Array<{ question: string; answer: string }>;
    };
  };
}
```

## 🚀 Déploiement Vercel

Cette architecture est **100% compatible Vercel** :

✅ **Server Components** : Standard Next.js 15  
✅ **Imports dynamiques** : `import()` géré nativement  
✅ **generateStaticParams** : SSG au build  
✅ **generateMetadata** : SEO optimal  
✅ **Edge-ready** : Pas de dépendance Node.js

Au build, Vercel va :

1. Pré-générer toutes les pages `/tools/[slug]`
2. Optimiser les imports dynamiques
3. Générer les métadonnées SEO
4. Créer un bundle minimal par outil

## 🎨 Personnalisation

### Ajouter une catégorie

Modifier `_registry/types.ts` :

```typescript
export type ToolCategory =
  | "image"
  | "development"
  | "design"
  | "productivity"
  | "ma-nouvelle-categorie"; // ✅ Ajoutez ici
```

### Modifier le layout

Éditer `_components/ToolLayoutDesktop.tsx` ou `ToolLayoutMobile.tsx` :

- Tous les outils héritent automatiquement des changements
- Préserve la cohérence visuelle

### Ajouter des icônes

Utiliser `lucide-react` (déjà installé) :

```tsx
import { Zap, Star, Heart } from "lucide-react";
```

## 📝 Checklist ajout outil

- [ ] Copier un dossier existant (`png-to-webp` ou `career-timeline`)
- [ ] Renommer le dossier avec le slug de l'outil (kebab-case)
- [ ] Modifier `index.ts` → changer `TOOL_SLUG`
- [ ] Modifier `i18n.ts` → traduire title, description, labels
- [ ] Modifier `seo.ts` → remplir les 3 langues (fr/en/es)
- [ ] Modifier `tool.client.tsx` ou `tool.server.tsx` → coder la logique
- [ ] Ajouter 1 ligne dans `_registry/tools.registry.ts`
- [ ] Rebuild : `cd apps/lastbrain && pnpm build:modules`
- [ ] Tester : `http://localhost:3000/tools/mon-outil`

## 🆘 Troubleshooting

### L'outil n'apparaît pas dans la liste

1. Vérifier que le slug dans `index.ts` correspond au nom du dossier
2. Vérifier que l'outil est déclaré dans `tools.registry.ts`
3. Vérifier que `status` est `"active"` (pas `"coming-soon"`)
4. Rebuild : `pnpm build:modules`

### Erreur TypeScript

```bash
# Vérifier les types
cd packages/module-tools
pnpm build
```

### L'outil fonctionne en dev mais pas en production

1. Vérifier que le composant n'utilise pas de dépendance Node.js
2. Pour les Client Components : ajouter `"use client"` en haut du fichier
3. Vérifier les imports : utiliser chemins relatifs corrects

## 📚 Exemples complets

Référez-vous aux outils existants :

- **`png-to-webp/`** : Exemple complet d'outil interactif (upload, canvas, download)
- **`career-timeline/`** : Exemple complet d'outil statique (affichage de données)

Ces deux outils contiennent tous les patterns nécessaires pour créer n'importe quel type d'outil.

---

**🎯 En résumé** : Copiez un dossier, modifiez 4 fichiers, ajoutez 1 ligne dans le registry, rebuild. C'est tout !