463 lines
18 KiB
Markdown
463 lines
18 KiB
Markdown
# Schéma de base de données — Xpeditis
|
|
|
|
PostgreSQL 15 — 21 tables.
|
|
|
|
**Extensions requises** : `uuid-ossp`, `pg_trgm`
|
|
|
|
---
|
|
|
|
## Vue d'ensemble des tables
|
|
|
|
| Table | Description |
|
|
|-------|-------------|
|
|
| organizations | Organisations (transitaires, transporteurs) |
|
|
| users | Comptes utilisateurs |
|
|
| carriers | Transporteurs maritimes |
|
|
| ports | Base de données des ports (UN/LOCODE) |
|
|
| rate_quotes | Cotations de tarifs carriers |
|
|
| bookings | Réservations standard |
|
|
| containers | Conteneurs liés aux réservations |
|
|
| csv_bookings | Réservations créées via CSV |
|
|
| csv_rate_configs | Configuration des carriers CSV |
|
|
| carrier_profiles | Profils portail carrier |
|
|
| carrier_activities | Activités du portail carrier |
|
|
| audit_logs | Journal d'audit des actions |
|
|
| notifications | Notifications push (WebSocket) |
|
|
| webhooks | Configuration des webhooks tiers |
|
|
| subscriptions | Abonnements Stripe |
|
|
| licenses | Licences d'utilisation |
|
|
| api_keys | Clés API (auth alternative au JWT) |
|
|
| invitation_tokens | Tokens d'invitation utilisateur |
|
|
| password_reset_tokens | Tokens de réinitialisation mot de passe |
|
|
| cookie_consents | Consentements RGPD cookies |
|
|
| blog_posts | Articles de blog |
|
|
|
|
---
|
|
|
|
## Tables détaillées
|
|
|
|
### organizations
|
|
|
|
| Colonne | Type | Contraintes | Description |
|
|
|---------|------|-------------|-------------|
|
|
| id | UUID | PK | Identifiant |
|
|
| name | VARCHAR(255) | NOT NULL, UNIQUE | Nom de l'organisation |
|
|
| type | VARCHAR(50) | NOT NULL | FREIGHT_FORWARDER, CARRIER, SHIPPER |
|
|
| scac | CHAR(4) | UNIQUE, NULLABLE | Standard Carrier Alpha Code |
|
|
| address_street | VARCHAR(255) | NOT NULL | Adresse |
|
|
| address_city | VARCHAR(100) | NOT NULL | Ville |
|
|
| address_state | VARCHAR(100) | NULLABLE | État/Province |
|
|
| address_postal_code | VARCHAR(20) | NOT NULL | Code postal |
|
|
| address_country | CHAR(2) | NOT NULL | Code pays ISO 3166-1 |
|
|
| logo_url | TEXT | NULLABLE | URL du logo |
|
|
| documents | JSONB | DEFAULT '[]' | Documents compliance |
|
|
| siret | VARCHAR(20) | NULLABLE | SIRET (entreprises françaises) |
|
|
| status_badge | VARCHAR(50) | NULLABLE | Badge de statut Pappers |
|
|
| is_carrier | BOOLEAN | DEFAULT FALSE | Est un carrier (portail) |
|
|
| is_active | BOOLEAN | DEFAULT TRUE | Compte actif |
|
|
| created_at | TIMESTAMP | DEFAULT NOW() | Création |
|
|
| updated_at | TIMESTAMP | DEFAULT NOW() | Mise à jour |
|
|
|
|
---
|
|
|
|
### users
|
|
|
|
| Colonne | Type | Contraintes | Description |
|
|
|---------|------|-------------|-------------|
|
|
| id | UUID | PK | Identifiant |
|
|
| organization_id | UUID | FK organizations | Organisation |
|
|
| email | VARCHAR(255) | NOT NULL, UNIQUE | Email (minuscules) |
|
|
| password_hash | VARCHAR(255) | NOT NULL | Hash Argon2 |
|
|
| role | VARCHAR(50) | NOT NULL | ADMIN, MANAGER, USER, VIEWER, CARRIER |
|
|
| first_name | VARCHAR(100) | NOT NULL | Prénom |
|
|
| last_name | VARCHAR(100) | NOT NULL | Nom |
|
|
| phone_number | VARCHAR(20) | NULLABLE | Téléphone |
|
|
| is_email_verified | BOOLEAN | DEFAULT FALSE | Email vérifié |
|
|
| is_active | BOOLEAN | DEFAULT TRUE | Compte actif |
|
|
| preferred_language | VARCHAR(10) | DEFAULT 'fr' | Langue préférée (fr, en) |
|
|
| last_login_at | TIMESTAMP | NULLABLE | Dernière connexion |
|
|
| created_at | TIMESTAMP | DEFAULT NOW() | Création |
|
|
| updated_at | TIMESTAMP | DEFAULT NOW() | Mise à jour |
|
|
|
|
Index : `idx_users_email`, `idx_users_organization`, `idx_users_role`
|
|
|
|
---
|
|
|
|
### carriers
|
|
|
|
| Colonne | Type | Contraintes | Description |
|
|
|---------|------|-------------|-------------|
|
|
| id | UUID | PK | Identifiant |
|
|
| name | VARCHAR(255) | NOT NULL | Nom (ex: "Maersk") |
|
|
| code | VARCHAR(50) | NOT NULL, UNIQUE | Code (ex: "MAERSK") |
|
|
| scac | CHAR(4) | NOT NULL, UNIQUE | Standard Carrier Alpha Code |
|
|
| logo_url | TEXT | NULLABLE | URL du logo |
|
|
| website | TEXT | NULLABLE | Site web |
|
|
| api_config | JSONB | NULLABLE | Config API (credentials, timeout) |
|
|
| is_active | BOOLEAN | DEFAULT TRUE | Actif |
|
|
| supports_api | BOOLEAN | DEFAULT FALSE | Intégration API disponible |
|
|
| created_at | TIMESTAMP | DEFAULT NOW() | Création |
|
|
| updated_at | TIMESTAMP | DEFAULT NOW() | Mise à jour |
|
|
|
|
Carriers seedés : Maersk (MAEU), MSC (MSCU), CMA CGM (CMDU), Hapag-Lloyd (HLCU), ONE (ONEY)
|
|
|
|
---
|
|
|
|
### ports
|
|
|
|
| Colonne | Type | Contraintes | Description |
|
|
|---------|------|-------------|-------------|
|
|
| id | UUID | PK | Identifiant |
|
|
| code | CHAR(5) | NOT NULL, UNIQUE | UN/LOCODE (ex: "NLRTM") |
|
|
| name | VARCHAR(255) | NOT NULL | Nom du port |
|
|
| city | VARCHAR(255) | NOT NULL | Ville |
|
|
| country | CHAR(2) | NOT NULL | Code pays |
|
|
| country_name | VARCHAR(100) | NOT NULL | Nom du pays |
|
|
| latitude | DECIMAL(9,6) | NOT NULL | Latitude |
|
|
| longitude | DECIMAL(9,6) | NOT NULL | Longitude |
|
|
| timezone | VARCHAR(50) | NULLABLE | Fuseau horaire IANA |
|
|
| is_active | BOOLEAN | DEFAULT TRUE | Actif |
|
|
|
|
Index GIN pour recherche floue : `idx_ports_name_trgm`, `idx_ports_city_trgm`
|
|
|
|
---
|
|
|
|
### rate_quotes
|
|
|
|
| Colonne | Type | Contraintes | Description |
|
|
|---------|------|-------------|-------------|
|
|
| id | UUID | PK | Identifiant |
|
|
| carrier_id | UUID | FK carriers | Carrier |
|
|
| carrier_name | VARCHAR(255) | NOT NULL | Nom carrier (dénormalisé) |
|
|
| carrier_code | VARCHAR(50) | NOT NULL | Code carrier (dénormalisé) |
|
|
| origin_code | CHAR(5) | NOT NULL | Port d'origine |
|
|
| destination_code | CHAR(5) | NOT NULL | Port de destination |
|
|
| base_freight | DECIMAL(10,2) | NOT NULL | Fret de base |
|
|
| surcharges | JSONB | DEFAULT '[]' | Surcharges (BAF, CAF, etc.) |
|
|
| total_amount | DECIMAL(10,2) | NOT NULL | Prix total |
|
|
| currency | CHAR(3) | NOT NULL | Devise ISO 4217 |
|
|
| container_type | VARCHAR(20) | NOT NULL | Type conteneur (20GP, 40HC, etc.) |
|
|
| mode | VARCHAR(10) | NOT NULL | FCL ou LCL |
|
|
| etd | TIMESTAMP | NOT NULL | Départ estimé |
|
|
| eta | TIMESTAMP | NOT NULL | Arrivée estimée |
|
|
| transit_days | INTEGER | NOT NULL | Jours de transit |
|
|
| route | JSONB | NOT NULL | Escales |
|
|
| availability | INTEGER | NOT NULL | Disponibilité conteneurs |
|
|
| valid_until | TIMESTAMP | NOT NULL | Expiration (created_at + 15 min) |
|
|
|
|
---
|
|
|
|
### bookings
|
|
|
|
| Colonne | Type | Contraintes | Description |
|
|
|---------|------|-------------|-------------|
|
|
| id | UUID | PK | Identifiant |
|
|
| booking_number | VARCHAR(20) | NOT NULL, UNIQUE | Format WCM-YYYY-XXXXXX |
|
|
| user_id | UUID | FK users | Utilisateur créateur |
|
|
| organization_id | UUID | FK organizations | Organisation |
|
|
| rate_quote_id | UUID | FK rate_quotes, NULLABLE | Cotation source |
|
|
| carrier_id | UUID | FK carriers | Carrier |
|
|
| status | VARCHAR(50) | NOT NULL | draft, confirmed, shipped, delivered, cancelled |
|
|
| shipper | JSONB | NOT NULL | Infos expéditeur |
|
|
| consignee | JSONB | NOT NULL | Infos destinataire |
|
|
| cargo | JSONB | NULLABLE | Détails marchandise |
|
|
| notes | TEXT | NULLABLE | Notes internes |
|
|
| created_at | TIMESTAMP | DEFAULT NOW() | Création |
|
|
| updated_at | TIMESTAMP | DEFAULT NOW() | Mise à jour |
|
|
|
|
---
|
|
|
|
### containers
|
|
|
|
| Colonne | Type | Contraintes | Description |
|
|
|---------|------|-------------|-------------|
|
|
| id | UUID | PK | Identifiant |
|
|
| booking_id | UUID | FK bookings, NULLABLE | Réservation |
|
|
| type | VARCHAR(20) | NOT NULL | 20GP, 40HC, 40RF, etc. |
|
|
| category | VARCHAR(20) | NOT NULL | DRY, REEFER, OPEN_TOP, FLAT_RACK, TANK |
|
|
| container_number | VARCHAR(11) | NULLABLE, UNIQUE | ISO 6346 |
|
|
| seal_number | VARCHAR(50) | NULLABLE | Numéro de plomb |
|
|
| vgm | INTEGER | NULLABLE | Masse Brute Vérifiée (kg) |
|
|
| is_hazmat | BOOLEAN | DEFAULT FALSE | Marchandise dangereuse |
|
|
| imo_class | VARCHAR(10) | NULLABLE | Classe IMO |
|
|
| cargo_description | TEXT | NULLABLE | Description de la marchandise |
|
|
|
|
---
|
|
|
|
### csv_bookings
|
|
|
|
| Colonne | Type | Contraintes | Description |
|
|
|---------|------|-------------|-------------|
|
|
| id | UUID | PK | Identifiant |
|
|
| organization_id | UUID | FK organizations | Organisation |
|
|
| carrier_id | UUID | FK carriers, NULLABLE | Carrier assigné |
|
|
| booking_number | VARCHAR(50) | NOT NULL, UNIQUE | Numéro de réservation |
|
|
| shipper_name | VARCHAR(255) | NOT NULL | Expéditeur |
|
|
| consignee_name | VARCHAR(255) | NOT NULL | Destinataire |
|
|
| origin_port | CHAR(5) | NOT NULL | Port d'origine (UN/LOCODE) |
|
|
| destination_port | CHAR(5) | NOT NULL | Port de destination |
|
|
| container_type | VARCHAR(20) | NOT NULL | Type conteneur |
|
|
| commodity | TEXT | NULLABLE | Marchandise |
|
|
| weight_kg | DECIMAL(10,2) | NULLABLE | Poids |
|
|
| status | VARCHAR(50) | NOT NULL | pending, accepted, rejected, in_transit, delivered |
|
|
| carrier_magic_link_token | VARCHAR(255) | NULLABLE | Token lien magique carrier |
|
|
| carrier_magic_link_expires_at | TIMESTAMP | NULLABLE | Expiration du token |
|
|
| carrier_password_hash | VARCHAR(255) | NULLABLE | Hash mdp portail carrier |
|
|
| notes | TEXT | NULLABLE | Notes |
|
|
| documents | JSONB | DEFAULT '[]' | Documents joints |
|
|
| created_at | TIMESTAMP | DEFAULT NOW() | Création |
|
|
| updated_at | TIMESTAMP | DEFAULT NOW() | Mise à jour |
|
|
|
|
---
|
|
|
|
### csv_rate_configs
|
|
|
|
| Colonne | Type | Contraintes | Description |
|
|
|---------|------|-------------|-------------|
|
|
| id | UUID | PK | Identifiant |
|
|
| company_name | VARCHAR(255) | NOT NULL, UNIQUE | Nom du carrier CSV |
|
|
| csv_file_path | VARCHAR(500) | NOT NULL | Chemin fichier CSV |
|
|
| type | VARCHAR(50) | DEFAULT 'CSV_ONLY' | CSV_ONLY ou CSV_AND_API |
|
|
| has_api | BOOLEAN | DEFAULT FALSE | A une API |
|
|
| api_connector | VARCHAR(100) | NULLABLE | Identifiant du connecteur API |
|
|
| is_active | BOOLEAN | DEFAULT TRUE | Actif |
|
|
| uploaded_at | TIMESTAMP | NOT NULL | Upload |
|
|
| uploaded_by | UUID | FK users, NULLABLE | Uploadé par |
|
|
| row_count | INTEGER | NULLABLE | Nombre de lignes |
|
|
|
|
---
|
|
|
|
### carrier_profiles
|
|
|
|
| Colonne | Type | Contraintes | Description |
|
|
|---------|------|-------------|-------------|
|
|
| id | UUID | PK | Identifiant |
|
|
| organization_id | UUID | FK organizations, UNIQUE | Organisation carrier |
|
|
| carrier_code | VARCHAR(50) | NOT NULL | Code carrier |
|
|
| contact_email | VARCHAR(255) | NOT NULL | Email de contact |
|
|
| contact_name | VARCHAR(255) | NULLABLE | Nom du contact |
|
|
| is_active | BOOLEAN | DEFAULT TRUE | Actif |
|
|
| created_at | TIMESTAMP | DEFAULT NOW() | Création |
|
|
|
|
---
|
|
|
|
### carrier_activities
|
|
|
|
| Colonne | Type | Contraintes | Description |
|
|
|---------|------|-------------|-------------|
|
|
| id | UUID | PK | Identifiant |
|
|
| carrier_profile_id | UUID | FK carrier_profiles | Profil carrier |
|
|
| csv_booking_id | UUID | FK csv_bookings | Réservation CSV |
|
|
| action | VARCHAR(50) | NOT NULL | ACCEPTED, REJECTED, VIEWED, DOCUMENT_UPLOADED |
|
|
| notes | TEXT | NULLABLE | Notes de l'action |
|
|
| created_at | TIMESTAMP | DEFAULT NOW() | Création |
|
|
|
|
---
|
|
|
|
### audit_logs
|
|
|
|
| Colonne | Type | Contraintes | Description |
|
|
|---------|------|-------------|-------------|
|
|
| id | UUID | PK | Identifiant |
|
|
| user_id | UUID | FK users, NULLABLE | Utilisateur |
|
|
| organization_id | UUID | FK organizations, NULLABLE | Organisation |
|
|
| action | VARCHAR(100) | NOT NULL | Type d'action (26 types) |
|
|
| resource_type | VARCHAR(50) | NULLABLE | Type de ressource |
|
|
| resource_id | VARCHAR(255) | NULLABLE | ID de la ressource |
|
|
| status | VARCHAR(20) | NOT NULL | SUCCESS, FAILURE, WARNING |
|
|
| metadata | JSONB | NULLABLE | Données supplémentaires |
|
|
| ip_address | VARCHAR(45) | NULLABLE | Adresse IP |
|
|
| user_agent | TEXT | NULLABLE | User agent |
|
|
| created_at | TIMESTAMP | DEFAULT NOW() | Création |
|
|
|
|
Index : `idx_audit_logs_user_id`, `idx_audit_logs_action`, `idx_audit_logs_created_at`
|
|
|
|
---
|
|
|
|
### notifications
|
|
|
|
| Colonne | Type | Contraintes | Description |
|
|
|---------|------|-------------|-------------|
|
|
| id | UUID | PK | Identifiant |
|
|
| user_id | UUID | FK users | Destinataire |
|
|
| type | VARCHAR(50) | NOT NULL | BOOKING_CREATED, DOCUMENT_UPLOADED, etc. (9 types) |
|
|
| title | VARCHAR(255) | NOT NULL | Titre |
|
|
| message | TEXT | NOT NULL | Message |
|
|
| data | JSONB | NULLABLE | Données associées |
|
|
| priority | VARCHAR(20) | NOT NULL | LOW, MEDIUM, HIGH, URGENT |
|
|
| read | BOOLEAN | DEFAULT FALSE | Lu |
|
|
| read_at | TIMESTAMP | NULLABLE | Date de lecture |
|
|
| created_at | TIMESTAMP | DEFAULT NOW() | Création |
|
|
|
|
---
|
|
|
|
### webhooks
|
|
|
|
| Colonne | Type | Contraintes | Description |
|
|
|---------|------|-------------|-------------|
|
|
| id | UUID | PK | Identifiant |
|
|
| organization_id | UUID | FK organizations | Organisation |
|
|
| url | TEXT | NOT NULL | URL cible |
|
|
| secret | VARCHAR(255) | NOT NULL | Secret HMAC SHA-256 |
|
|
| events | JSONB | NOT NULL | Événements souscrits |
|
|
| is_active | BOOLEAN | DEFAULT TRUE | Actif |
|
|
| last_triggered_at | TIMESTAMP | NULLABLE | Dernier déclenchement |
|
|
| failure_count | INTEGER | DEFAULT 0 | Compteur d'échecs |
|
|
| created_at | TIMESTAMP | DEFAULT NOW() | Création |
|
|
|
|
---
|
|
|
|
### subscriptions
|
|
|
|
| Colonne | Type | Contraintes | Description |
|
|
|---------|------|-------------|-------------|
|
|
| id | UUID | PK | Identifiant |
|
|
| organization_id | UUID | FK organizations, UNIQUE | Organisation |
|
|
| stripe_customer_id | VARCHAR(255) | NULLABLE | ID client Stripe |
|
|
| stripe_subscription_id | VARCHAR(255) | NULLABLE | ID abonnement Stripe |
|
|
| plan | VARCHAR(50) | NOT NULL | FREE, BRONZE, SILVER, GOLD, PLATINIUM |
|
|
| status | VARCHAR(50) | NOT NULL | active, past_due, cancelled, trialing, pending_payment, pending_bank_transfer |
|
|
| current_period_start | TIMESTAMP | NULLABLE | Début de période |
|
|
| current_period_end | TIMESTAMP | NULLABLE | Fin de période |
|
|
| billing_interval | VARCHAR(20) | NULLABLE | monthly, yearly |
|
|
| commission_rate | DECIMAL(5,4) | DEFAULT 0 | Taux de commission Xpeditis |
|
|
| created_at | TIMESTAMP | DEFAULT NOW() | Création |
|
|
| updated_at | TIMESTAMP | DEFAULT NOW() | Mise à jour |
|
|
|
|
---
|
|
|
|
### licenses
|
|
|
|
| Colonne | Type | Contraintes | Description |
|
|
|---------|------|-------------|-------------|
|
|
| id | UUID | PK | Identifiant |
|
|
| organization_id | UUID | FK organizations | Organisation |
|
|
| feature | VARCHAR(100) | NOT NULL | Fonctionnalité activée |
|
|
| is_active | BOOLEAN | DEFAULT TRUE | Actif |
|
|
| valid_until | TIMESTAMP | NULLABLE | Expiration |
|
|
| created_at | TIMESTAMP | DEFAULT NOW() | Création |
|
|
|
|
---
|
|
|
|
### api_keys
|
|
|
|
| Colonne | Type | Contraintes | Description |
|
|
|---------|------|-------------|-------------|
|
|
| id | UUID | PK | Identifiant |
|
|
| organization_id | UUID | FK organizations | Organisation |
|
|
| user_id | UUID | FK users | Créateur |
|
|
| name | VARCHAR(255) | NOT NULL | Nom de la clé |
|
|
| key_hash | VARCHAR(255) | NOT NULL | Hash Argon2 de la clé |
|
|
| key_prefix | VARCHAR(10) | NOT NULL | Préfixe visible (ex: xped_) |
|
|
| last_used_at | TIMESTAMP | NULLABLE | Dernière utilisation |
|
|
| expires_at | TIMESTAMP | NULLABLE | Expiration |
|
|
| is_active | BOOLEAN | DEFAULT TRUE | Actif |
|
|
| created_at | TIMESTAMP | DEFAULT NOW() | Création |
|
|
|
|
---
|
|
|
|
### invitation_tokens
|
|
|
|
| Colonne | Type | Contraintes | Description |
|
|
|---------|------|-------------|-------------|
|
|
| id | UUID | PK | Identifiant |
|
|
| organization_id | UUID | FK organizations | Organisation |
|
|
| email | VARCHAR(255) | NOT NULL | Email invité |
|
|
| token | VARCHAR(255) | NOT NULL, UNIQUE | Token d'invitation |
|
|
| role | VARCHAR(50) | NOT NULL | Rôle assigné |
|
|
| expires_at | TIMESTAMP | NOT NULL | Expiration (24h) |
|
|
| used_at | TIMESTAMP | NULLABLE | Utilisé le |
|
|
| created_by | UUID | FK users | Créateur |
|
|
|
|
---
|
|
|
|
### password_reset_tokens
|
|
|
|
| Colonne | Type | Contraintes | Description |
|
|
|---------|------|-------------|-------------|
|
|
| id | UUID | PK | Identifiant |
|
|
| user_id | UUID | FK users | Utilisateur |
|
|
| token | VARCHAR(255) | NOT NULL, UNIQUE | Token de réinitialisation |
|
|
| expires_at | TIMESTAMP | NOT NULL | Expiration (1h) |
|
|
| used_at | TIMESTAMP | NULLABLE | Utilisé le |
|
|
| created_at | TIMESTAMP | DEFAULT NOW() | Création |
|
|
|
|
---
|
|
|
|
### cookie_consents
|
|
|
|
| Colonne | Type | Contraintes | Description |
|
|
|---------|------|-------------|-------------|
|
|
| id | UUID | PK | Identifiant |
|
|
| user_id | UUID | FK users, NULLABLE | Utilisateur (si connecté) |
|
|
| session_id | VARCHAR(255) | NULLABLE | Session anonyme |
|
|
| analytics | BOOLEAN | NOT NULL | Consentement analytics |
|
|
| marketing | BOOLEAN | NOT NULL | Consentement marketing |
|
|
| ip_address | VARCHAR(45) | NULLABLE | IP |
|
|
| created_at | TIMESTAMP | DEFAULT NOW() | Création |
|
|
|
|
---
|
|
|
|
### blog_posts
|
|
|
|
| Colonne | Type | Contraintes | Description |
|
|
|---------|------|-------------|-------------|
|
|
| id | UUID | PK | Identifiant |
|
|
| slug | VARCHAR(255) | NOT NULL, UNIQUE | Slug URL |
|
|
| title_fr | VARCHAR(500) | NOT NULL | Titre en français |
|
|
| title_en | VARCHAR(500) | NULLABLE | Titre en anglais |
|
|
| content_fr | TEXT | NOT NULL | Contenu en français |
|
|
| content_en | TEXT | NULLABLE | Contenu en anglais |
|
|
| excerpt_fr | TEXT | NULLABLE | Extrait français |
|
|
| excerpt_en | TEXT | NULLABLE | Extrait anglais |
|
|
| cover_image_url | TEXT | NULLABLE | Image de couverture |
|
|
| author_id | UUID | FK users | Auteur |
|
|
| is_published | BOOLEAN | DEFAULT FALSE | Publié |
|
|
| published_at | TIMESTAMP | NULLABLE | Date de publication |
|
|
| tags | JSONB | DEFAULT '[]' | Tags |
|
|
| created_at | TIMESTAMP | DEFAULT NOW() | Création |
|
|
| updated_at | TIMESTAMP | DEFAULT NOW() | Mise à jour |
|
|
|
|
---
|
|
|
|
## Relations principales
|
|
|
|
```
|
|
organizations 1──* users
|
|
organizations 1──1 subscriptions
|
|
organizations 1──* licenses
|
|
organizations 1──* api_keys
|
|
organizations 1──* webhooks
|
|
organizations 1──* bookings
|
|
organizations 1──* csv_bookings
|
|
organizations 1──1 carrier_profiles
|
|
|
|
users 1──* bookings
|
|
users 1──* audit_logs
|
|
users 1──* notifications
|
|
users 1──* api_keys
|
|
|
|
bookings 1──* containers
|
|
bookings 1──1 rate_quotes (optionnel)
|
|
|
|
csv_bookings 1──* carrier_activities (via carrier_profiles)
|
|
carrier_profiles 1──* carrier_activities
|
|
```
|
|
|
|
---
|
|
|
|
## Stratégie de migrations
|
|
|
|
Les migrations sont dans `apps/backend/src/infrastructure/persistence/typeorm/migrations/`.
|
|
Ne jamais modifier une migration déjà appliquée — créer une nouvelle migration.
|
|
|
|
```bash
|
|
cd apps/backend
|
|
npm run migration:generate -- src/infrastructure/persistence/typeorm/migrations/NomMigration
|
|
npm run migration:run
|
|
```
|
|
|
|
---
|
|
|
|
*Dernière mise à jour : Mai 2026 — 21 tables*
|