# Schéma complet des données

## Sources recensées

- Schéma D1/SQLite : `db/schema.ts`
- Migrations historiques D1 : `drizzle/0000...sql` à `0002...sql`
- Schéma PostgreSQL courant : `db/postgres/schema.ts`
- Migration PostgreSQL : `drizzle-postgres/0000_opposite_lake.sql`
- Types métier : `lib/events/types.ts`

Le projet contient une seule table métier : `events`. Il n'existe aucune relation ni clé étrangère.

## Table `events`

| Colonne physique | Type D1 | Type PostgreSQL | Null | Défaut | Contraintes | Champ TypeScript |
| --- | --- | --- | --- | --- | --- | --- |
| `id` | `integer` | `serial` | non | auto-incrément | clé primaire | `id: number` |
| `slug` | `text` | `text` | non | aucun | unique | `slug: string` |
| `management_token` | `text` | `text` | oui | `NULL` | unique | `managementToken: string \| null` |
| `email` | `text` | `text` | non | aucun dans le schéma final | — | `email: string` |
| `image_url` | `text` | `text` | oui | `NULL` | — | `imageUrl: string \| null` |
| `title` | `text` | `text` | non | aucun | — | `title: string` |
| `category` | `text` | `text` | non | aucun | — | `category: string` |
| `date` | `text` | `text` | non | aucun | — | `date: string` |
| `time` | `text` | `text` | non | aucun | — | `time: string` |
| `location` | `text` | `text` | non | aucun | — | `location: string` |
| `description` | `text` | `text` | non | aucun | — | `description: string` |
| `price` | `text` | `text` | non | aucun | — | `price: string` |
| `updated_at` | `text` | `text` | non | horodatage courant | — | `updatedAt: string` |
| `created_at` | `text` | `text` | non | horodatage courant | — | `createdAt: string` |

## Index

| Nom logique | Colonnes | Type |
| --- | --- | --- |
| clé primaire de `events` | `id` | primaire, unique |
| `events_slug_unique` | `slug` | unique |
| `events_management_token_unique` | `management_token` | unique |

Aucun index explicite n'existe sur `created_at`, `category`, `date` ou `email`.

## Valeurs et formats observés

- `slug` : titre normalisé ASCII, suivi de `-` et de quatre caractères pseudo-aléatoires en base 36.
- `management_token` : deux UUID concaténés, le second sans tirets.
- `email` : chaîne nettoyée et mise en minuscules à la création.
- `category` : l'interface produit actuellement `Event’go` ou `Spiri’go`, mais la base n'impose aucune énumération.
- `date` : texte provenant d'un champ HTML `date`, attendu sous la forme `YYYY-MM-DD`.
- `time` : texte provenant d'un champ HTML `time`, attendu sous la forme `HH:MM`.
- `price` : interface limitée à `Gratuit`, `Prix libre`, `Payant`, sans contrainte en base.
- `image_url` : normalement `/api/images/{uuid}.{jpg|png|webp}`.
- `created_at` et `updated_at` : texte ; PostgreSQL produit une représentation textuelle de `CURRENT_TIMESTAMP`, tandis que les mises à jour utilisent `Date.toISOString()`. Le format historique peut donc varier.

## Historique du prototype non déployé

La table initiale ne contenait ni e-mail, ni jeton de gestion, ni image, ni `updated_at`.

Les migrations suivantes ont ajouté :

- `email` avec défaut historique `''` ;
- `management_token`, nullable ;
- `image_url`, nullable ;
- `updated_at` avec défaut historique `''` ;
- l'index unique sur `management_token`.

Le schéma D1 du prototype autorisait :

- `email = ''` ;
- `management_token IS NULL` ;
- `image_url IS NULL` ;
- `updated_at = ''`.

Event'Go n'ayant jamais été déployé, aucune donnée D1 ou PostgreSQL n'existe à
reprendre. Aucun import ni script de migration ne sera développé.

## Modèle MySQL définitif de l'étape 2

Le schéma exécutable se trouve dans `php/schema.sql`.

| Colonne | Type MySQL envisagé | Justification |
| --- | --- | --- |
| `id` | `BIGINT UNSIGNED AUTO_INCREMENT` | marge durable, clé primaire |
| `slug` | `VARCHAR(191)` | index unique compatible |
| `management_token` | `VARCHAR(191) NULL` | index unique, anciennes lignes nulles |
| `email` | `VARCHAR(320)` | longueur maximale d'adresse |
| `image_url` | `VARCHAR(2048) NULL` | URL ou chemin |
| `title` | `VARCHAR(255)` | titre court |
| `category` | `VARCHAR(64)` | valeur métier extensible |
| `date` | `VARCHAR(32)` | conserve exactement la sérialisation API |
| `time` | `VARCHAR(32)` | conserve exactement la sérialisation API |
| `location` | `VARCHAR(500)` | lieu |
| `description` | `TEXT` | contenu libre |
| `price` | `VARCHAR(64)` | libellé actuel |
| `updated_at` | `VARCHAR(40)` | conserve les dates ISO retournées |
| `created_at` | `VARCHAR(40)` | conserve les dates ISO retournées |

La base étant neuve, les horodatages sont générés directement en UTC par PHP.

## Relations et règles métier absentes

- Aucune table utilisateur.
- Aucun compte ni mot de passe.
- Aucune relation événement-organisateur.
- Aucune table de catégories.
- Aucune table d'images.
- Aucune réservation malgré le bouton visuel « Je participe ».
- Aucun statut de publication, brouillon ou expiration.
- Aucune suppression logique.
