> ## Documentation Index
> Fetch the complete documentation index at: https://docs-kit.lucdidion.lu/llms.txt
> Use this file to discover all available pages before exploring further.

# Feature Tool Packs - Collections curées

> Bundles thématiques d outils pour des besoins spécifiques

## Vue d'ensemble

Les **Tool Packs** sont des collections curées d'outils regroupés par thème ou cas d'usage. Ils simplifient le choix en proposant des ensembles cohérents et testés.

**Objectif :** Éviter la paralysie du choix en proposant des sélections prêtes à l'emploi.

**Exemples de packs :**

* Starter Pack (essentiels pour débuter)
* Communication & Email
* Automatisation
* Paiements & Dons
* Sites Web

***

## Architecture technique

### Tables de base de données

#### Table `tool_packs`

```sql theme={null}
CREATE TABLE tool_packs (
  id UUID PRIMARY KEY,
  title TEXT NOT NULL,
  description TEXT NOT NULL,
  difficulty TEXT,
  icon TEXT DEFAULT 'Package',
  color TEXT DEFAULT 'blue',
  display_order INTEGER DEFAULT 0,
  status TEXT CHECK (status IN ('active', 'draft')) DEFAULT 'active',
  created_at TIMESTAMPTZ DEFAULT NOW(),
  updated_at TIMESTAMPTZ DEFAULT NOW()
);
```

#### Table `pack_tools` (Jointure Many-to-Many)

```sql theme={null}
CREATE TABLE pack_tools (
  id UUID PRIMARY KEY,
  pack_id UUID REFERENCES tool_packs(id) ON DELETE CASCADE,
  tool_id UUID REFERENCES tools(id) ON DELETE CASCADE,
  display_order INTEGER DEFAULT 0,
  created_at TIMESTAMPTZ DEFAULT NOW(),
  UNIQUE(pack_id, tool_id)
);
```

***

### API Layer (GraphQL)

**Fichier :** `src/api/packs.ts`

```typescript theme={null}
import { apiCall, apiCallVoid } from './base';
import { nhost } from './client';

export const packsApi = {
  /**
   * Liste tous les packs actifs avec nombre d'outils
   */
  async list(): Promise<Array<ToolPack & { tool_count: number }>> {
    const query = `
      query GetPacks {
        tool_packs(
          where: { status: { _eq: "active" } }
          order_by: { display_order: asc }
        ) {
          id title description difficulty icon color
          display_order status
          pack_tools_aggregate { aggregate { count } }
        }
      }
    `;
    return apiCall(
      () => nhost.graphql.request({ query }),
      'packs.list'
    );
  },

  /**
   * Récupère un pack avec ses outils enrichis
   */
  async getById(id: string): Promise<ToolPack & { tools: EnhancedTool[] }> {
    const query = `
      query GetPack($id: uuid!) {
        tool_packs_by_pk(id: $id) {
          id title description difficulty icon color
          pack_tools(order_by: { display_order: asc }) {
            display_order
            tool {
              id name description pricing_tier logo_url website_url
              category { name }
            }
          }
        }
      }
    `;
    return apiCall(
      () => nhost.graphql.request({ query, variables: { id } }),
      'packs.getById'
    );
  },

  /**
   * Ajoute un outil au pack
   */
  async addTool(packId: string, toolId: string, displayOrder?: number): Promise<void> {
    const mutation = `
      mutation AddPackTool($object: pack_tools_insert_input!) {
        insert_pack_tools_one(object: $object) { id }
      }
    `;
    await apiCallVoid(
      () => nhost.graphql.request({
        query: mutation,
        variables: { object: { pack_id: packId, tool_id: toolId, display_order: displayOrder || 0 } }
      }),
      'packs.addTool'
    );
  },

  /**
   * Retire un outil du pack
   */
  async removeTool(packId: string, toolId: string): Promise<void> {
    const mutation = `
      mutation RemovePackTool($packId: uuid!, $toolId: uuid!) {
        delete_pack_tools(where: {
          pack_id: { _eq: $packId },
          tool_id: { _eq: $toolId }
        }) { affected_rows }
      }
    `;
    await apiCallVoid(
      () => nhost.graphql.request({
        query: mutation,
        variables: { packId, toolId }
      }),
      'packs.removeTool'
    );
  },
};
```

***

## Structure d'un Tool Pack

### Métadonnées

```typescript theme={null}
interface ToolPack {
  id: string;
  title: string;           // "Starter Pack"
  description: string;     // "Essentiels pour débuter"
  difficulty?: string;     // "débutant", "intermédiaire", "expert"
  icon: string;            // "Rocket" (nom d'icône Lucide)
  color: string;           // "blue", "green", "orange", etc.
  display_order: number;
  status: 'active' | 'draft';
}
```

***

## Composants UI

### PackCard

```typescript theme={null}
// src/components/toolpacks/PackCard.tsx
import { getIconComponent } from '@/utils/icons';

export function PackCard({ pack, onClick }: PackCardProps) {
  const Icon = getIconComponent(pack.icon);

  const colorClasses = {
    blue: 'bg-blue-100 text-blue-600',
    green: 'bg-green-100 text-green-600',
    orange: 'bg-orange-100 text-orange-600',
    purple: 'bg-purple-100 text-purple-600',
    red: 'bg-red-100 text-red-600',
  };

  return (
    <div onClick={onClick} className="p-6 border rounded-lg hover:shadow-lg transition cursor-pointer">
      <div className={`inline-flex p-3 rounded-lg mb-4 ${colorClasses[pack.color]}`}>
        <Icon className="w-6 h-6" />
      </div>
      <h3 className="font-semibold text-lg mb-2">{pack.title}</h3>
      <p className="text-gray-600 text-sm mb-4">{pack.description}</p>
      <span className="text-gray-500 text-sm">
        {pack.tool_count} outil{pack.tool_count > 1 ? 's' : ''}
      </span>
    </div>
  );
}
```

***

## Permissions Hasura

* **public** : SELECT des packs actifs et de leurs `pack_tools`
* **admin** : CRUD complet sur `tool_packs` et `pack_tools`

***

## Bonnes pratiques

### ✅ À faire

* 3-7 outils par pack (ni trop, ni trop peu)
* Cohérence thématique forte
* Outils testés et approuvés
* Mix de pricing (gratuit + freemium)
* Starter Pack en premier dans l'affichage

### ❌ À éviter

* Packs trop larges ("Tous les outils")
* Doublons entre packs
* Outils obsolètes ou fermés
* Descriptions vagues

***

## Ressources

<CardGroup cols={2}>
  <Card title="Database Schema" icon="database" href="/database/schema">
    Structure des tables tool\_packs
  </Card>

  <Card title="API Layer" icon="plug" href="/development/api-layer">
    Utiliser l'API GraphQL
  </Card>

  <Card title="Admin Dashboard" icon="shield" href="/features/admin">
    Créer et gérer des packs
  </Card>

  <Card title="Quiz Feature" icon="clipboard-question" href="/features/quiz">
    Recommandations via quiz
  </Card>
</CardGroup>
