# Web

# Support et IA

# Ajouter un nouveau provider IA

## 1. Déclarer le provider et ses modèles

Dans `constantsVariable.js` :

```
const AI_PROVIDERS = {
    GEMINI: "gemini",
    OPENAI: "openai",
};

const AI_MODELS = {
    GEMINI_GENERATION: "gemini-3.5-flash-lite",
    GEMINI_EMBEDDING: "gemini-embedding-001",

    OPENAI_GENERATION: "gpt-example",
    OPENAI_EMBEDDING: "text-embedding-example",
};

const AI_PRICE_VERSIONS = {
    GEMINI: "vertex-global-standard-2026-09-29",
    OPENAI: "openai-standard-YYYY-MM-DD",
};
```

Configurer ensuite le provider actif dans `AI_CONFIG` :

```
const AI_CONFIG = {
    AI_PROVIDER: AI_PROVIDERS.OPENAI,
    AI_EMBEDDING_PROVIDER: AI_PROVIDERS.OPENAI,

    AI_MODEL: AI_MODELS.OPENAI_GENERATION,
    AI_EMBEDDING_MODEL: AI_MODELS.OPENAI_EMBEDDING,

    OPENAI_API_KEY: process.env.OPENAI_API_KEY,
};
```

Ne pas redéclarer les noms de modèles dans les fichiers du provider. Toujours importer `AI_MODELS` et `AI_PRICE_VERSIONS`.

> **Note sur les embeddings :** si on conserve toujours le provider et le modèle d'embedding déjà existants, toute la partie « nouveau provider d'embedding » peut être ignorée. Le nouveau provider peut servir uniquement à la génération, tandis que `AI_EMBEDDING_PROVIDER` et `AI_EMBEDDING_MODEL` restent configurés sur l'existant.

---

## 2. Créer le dossier du provider

Créer la structure suivante :

```
server/ai/provider/openai/
├── generation_provider.js
├── embedding_provider.js
├── tokenizer.js
├── pricing.js
└── context_cache.js
```

`context_cache.js` est facultatif si le provider ne supporte pas le cache. `embedding_provider.js` est également facultatif si on garde le provider d'embedding existant.

---

## 3. Implémenter le provider de génération

Le contrat se trouve dans :

```
server/ai/contract/generation_provider_contract.js
```

Le provider doit exposer les méthodes suivantes :

```
class OpenAIProvider {
    constructor(config, dependencies = {}) {
        this.name = AI_PROVIDERS.OPENAI;
        this.config = config;
        this.client = null;
    }

    async initialize() {}

    isReady() {}

    async countTokens(messages, options) {}

    async generate(request) {}
}
```

### Format normalisé des messages

```
{
    role: "user" | "assistant",
    content: [
        {
            type: "text",
            text: "Bonjour"
        },
        {
            type: "image",
            mimeType: "image/png",
            data: "base64..."
        }
    ]
}
```

Le provider doit convertir ce format vers celui de son SDK.

### Requête reçue par `generate()`

```
{
    operation,
    scope,
    prefix,
    messages,
    temperature,
    maxOutputTokens,
    thinkingLevel,
    inputTokenLimit,
    tokenCountTimeoutMs,
    timeoutMs,
    usage
}
```

### Réponse normalisée attendue

```
{
    text: "Réponse du modèle"
}
```

Aucun objet propre au SDK ne doit sortir du provider.

---

## 4. Implémenter le tokenizer

Créer `provider/openai/tokenizer.js` :

```
class OpenAITokenizer {
    constructor(client) {
        this.client = client;
    }

    async count(messages, options) {
        // Retourner un nombre entier de tokens.
    }

    normalizeUsage(providerUsage) {
        return {
            inputTokens: 0,
            cachedInputTokens: 0,
            outputTokens: 0,
            reasoningTokens: 0,
        };
    }
}
```

Les champs propres au SDK doivent rester dans ce fichier.

Exemples de champs qui ne doivent pas sortir du tokenizer :

```
promptTokenCount
candidatesTokenCount
input_tokens
output_tokens
cached_tokens
```

Le reste de l’application doit uniquement utiliser :

```
{
    inputTokens,
    cachedInputTokens,
    outputTokens,
    reasoningTokens
}
```

---

## 5. Implémenter le pricing

Créer `provider/openai/pricing.js`.

Importer les constantes partagées :

```
const {
    AI_PROVIDERS,
    AI_MODELS,
    AI_PRICE_VERSIONS,
} = require('../../../constantsVariable');
```

Implémenter le pricing :

```
class OpenAIPricing {
    constructor(config) {
        this.config = config;
        this.priceVersion = AI_PRICE_VERSIONS.OPENAI;
    }

    reservationCents(operation) {
        // Calculer le coût maximal pouvant être facturé.
    }
}
```

Le fichier peut aussi exposer :

```
function generationCost(usage) {}

function generationCeiling(inputTokens, outputTokens) {}

// Ajouter des opérations tarifées uniquement si le provider les utilise.
```

Les calculs doivent recevoir les statistiques normalisées, jamais les données brutes du SDK.

Un modèle sans pricing explicitement validé doit être rejeté.

---

## 6. Implémenter les embeddings (facultatif)

> **Cette étape peut être ignorée si on utilise toujours le même embedding déjà existant.** Dans ce cas, il n'est pas nécessaire d'implémenter un nouveau provider d'embedding ni de modifier la factory d'embedding.

Si un nouveau provider d'embedding est réellement nécessaire, le contrat se trouve dans :

```
server/ai/contract/embedding_provider_contract.js
```

Le provider doit exposer :

```
class OpenAIEmbeddingProvider {
    constructor(config, dependencies = {}) {}

    async initialize() {}

    isReady() {}

    assertInput(text) {}

    async embed(text, usage) {}
}
```

`embed()` doit retourner uniquement le vecteur :

```
[
    0.012,
    -0.034,
    0.056
]
```

`assertInput()` doit vérifier :

• Le modèle autorisé.

• La taille maximale du texte.

• La limite de tokens ou d’octets.

• La politique de coût applicable.

> Changer de modèle d’embedding nécessite généralement de réindexer toute la collection Chroma.

---

## 7. Enregistrer le provider de génération

Modifier :

```
server/ai/factory/generation_provider_factory.js
```

Importer le provider :

```
const {
    OpenAIProvider,
} = require("../provider/openai/generation_provider");
```

Ajouter le cas dans la factory :

```
switch (config.AI_PROVIDER) {
    case AI_PROVIDERS.GEMINI:
        provider = new GeminiProvider(config, dependencies);
        break;

    case AI_PROVIDERS.OPENAI:
        provider = new OpenAIProvider(config, dependencies);
        break;

    default:
        throw new Error(
            `Unsupported AI provider: ${config.AI_PROVIDER}`
        );
}
```

La factory valide automatiquement le contrat avant de retourner le provider.

---

## 8. Enregistrer le provider d’embedding (facultatif)

> **Ignorer cette étape si on garde le provider d'embedding existant.** Le provider de génération et celui d'embedding peuvent être différents.

Modifier :

```
server/ai/factory/embedding_provider_factory.js
```

Ajouter :

```
case AI_PROVIDERS.OPENAI:
    return assertEmbeddingProviderContract(
        new OpenAIEmbeddingProvider(config, dependencies)
    );
```

Exemple si OpenAI sert à la génération mais Gemini reste utilisé pour les embeddings :

```
AI_PROVIDER: AI_PROVIDERS.OPENAI,
AI_EMBEDDING_PROVIDER: AI_PROVIDERS.GEMINI,
```

---

## 9. Enregistrer le pricing

Modifier :

```
server/ai/factory/pricing_factory.js
```

Ajouter :

```
case AI_PROVIDERS.OPENAI:
    return assertPricingContract(
        new OpenAIPricing(config)
    );
```

---

## 10. Ajouter les tests

Vérifier au minimum :

• L’initialisation du SDK.

• Le contrat de génération.

• Le contrat d’embedding, uniquement si un nouveau provider d'embedding est ajouté.

• La conversion des messages normalisés.

• La conversion des images.

• Le comptage des tokens.

• La normalisation des statistiques d’utilisation.

• Le calcul des coûts.

• Les limites d’entrée.

• Les timeouts.

• Les réponses sans métadonnées.

• Le rejet des modèles sans pricing.

• Le rejet des providers inconnus.

Exécuter les tests AI :

```
npm run test:ai
```

---

## Checklist finale

• Provider ajouté dans `AI_PROVIDERS`.

• Modèles ajoutés dans `AI_MODELS`.

• Version tarifaire ajoutée dans `AI_PRICE_VERSIONS`.

• Dossier créé sous `ai/provider/<provider>/`.

• Contrat de génération respecté.

• Tokenizer spécifique isolé.

• Statistiques d’utilisation normalisées.

• Pricing explicitement validé.

• Contrat d’embedding respecté uniquement si un nouveau provider d'embedding est nécessaire.

• Provider enregistré dans les factories nécessaires.

• Aucun objet SDK ne sort du provider.

• Aucun champ propre au SDK n’est utilisé par le serveur générique.

• Tests AI réussis.

• Collection vectorielle réindexée uniquement si le modèle d’embedding change.

## Provider actuellement implémenté et règles de coût

Seul Gemini est enregistré dans les factories. Les exemples OpenAI ci-dessus décrivent un ajout possible, pas un provider déjà disponible. Le modèle de génération configuré est `gemini-3.5-flash-lite`, l’embedding reste `gemini-embedding-001`. Gemini utilise `@google/genai` via Vertex AI et `vertex_client.js`; `GOOGLE_CLOUD_PROJECT` est requis et la politique tarifaire actuelle impose `GOOGLE_CLOUD_LOCATION=global`.

`generation_provider.js` adapte les messages normalisés et le SDK; `generator.js` compte l’entrée, applique la limite et enregistre l’usage; `tokenizer.js` normalise input/cachedInput/output/reasoning. Le cache actuel est implicite : il n’y a plus de gestionnaire de cache de contexte explicite ni de coût de stockage associé dans ce provider.

Une nouvelle intégration doit enregistrer chaque opération payante avec `UsageMeter.begin()`, puis `complete()` lorsque l’usage est exploitable ou `failed()` sur erreur. `embed(text, usage)` accepte le meter à la recherche; l’ingestion peut appeler `embed(text)`. Les plafonds doivent inclure les tokens de raisonnement facturables. L’usage absent ou non pris en charge reste estimé au plafond réservé; les coûts ne doivent jamais être inventés à partir d’un usage manquant.

Les tests sont maintenant sous `test/ai/`. Depuis le backend : `npm run test:ai`, `npm run test:ai:coverage` ou `npm test -- --runInBand` pour toutes les suites.

# Pipeline RAG et système IA

## Vue d’ensemble

Le système IA du support UnikSim est basé sur une architecture RAG (*Retrieval-Augmented Generation*). Le backend NestJS orchestre la conversation de support, délègue la recherche et la génération au serveur IA interne, puis décide si une réponse IA peut être retournée ou si la conversation doit être escaladée vers un humain.

Les providers de génération et d'embedding sont volontairement indépendants. Cela permet de changer le modèle de génération sans modifier l'espace vectoriel existant dans Chroma.

## 1. Architecture des composants

Ce diagramme montre les responsabilités principales et les frontières entre le support, le serveur IA et les providers.

```mermaid
flowchart LR
    U[Utilisateur] --> FE[Frontend Angular / App]
    FE --> SS[SupportService - NestJS]
    SS --> AIS[AIService - NestJS]
    AIS -->|POST /ai/query| AI[Serveur IA interne]

    AI --> CG[CostGuard]
    AI --> UM[UsageMeter]
    AI --> EP[Embedding Provider]
    EP --> CH[(Chroma)]
    AI --> GP[Generation Provider]
    GP --> LLM[Gemini / autre LLM]

    SS --> DB[(MySQL)]
    SS -->|answered| FE
    SS -->|insufficient_context| ESC[Clarification puis suggestion d’escalade humaine]

```

### Responsabilités

- **SupportService** : persistance de la conversation, historique, contexte de récupération, pièces jointes et décision de réponse/escalade.
- **AIService** : client NestJS du serveur IA interne, validation et gestion des erreurs/timeouts.
- **Serveur IA** : recherche vectorielle, construction du contexte, génération, comptabilisation des coûts et garde-fous.
- **Embedding Provider** : transforme une requête ou un chunk documentaire en vecteur.
- **Chroma** : stocke et retourne les chunks sémantiquement proches.
- **Generation Provider** : encapsule le SDK du fournisseur LLM et retourne une réponse normalisée.

## 2. Pipeline d’ingestion documentaire

Les documents de support sont préparés à l'avance par le script d'ingestion. Le même provider/modèle d'embedding doit être utilisé à l'ingestion et à la recherche.

```mermaid
flowchart TD
    DOC[Documents PDF / Markdown] --> META[Lecture des métadonnées héritées]
    META --> VALID[Validation game / scope / audience / language]
    VALID --> PARSE[Parsing du document]
    PARSE --> CHUNK[Découpage en chunks avec overlap]
    CHUNK --> EMB[Embedding de chaque chunk]
    EMB --> IDS[IDs stables SHA-256]
    IDS --> UPSERT[Upsert par batch dans Chroma]
    UPSERT --> CLEAN[Suppression des anciens chunks devenus obsolètes]
    CLEAN --> ORPHAN[Nettoyage des documents supprimés ou déplacés]

    UPSERT -->|échec| ROLLBACK[Rollback des nouveaux IDs]

```

Le chunking privilégie les paragraphes et titres, puis découpe les blocs trop longs en phrases et en mots. Un chevauchement est conservé entre les chunks afin de limiter la perte de contexte.

## 3. Séquence complète d’une requête RAG

```mermaid
sequenceDiagram
    actor U as Utilisateur
    participant S as SupportService
    participant A as AIService
    participant R as Serveur IA
    participant E as Embedding Provider
    participant C as Chroma
    participant G as Generation Provider

    U->>S: Envoie un message
    S->>S: Sauvegarde message utilisateur
    S->>S: Charge historique + langue + retrievalContexts
    S->>A: queryRAG(...)
    A->>R: POST /ai/query + token interne
    R->>R: Réserve budget (CostGuard)
    R->>R: Construit la requête de recherche
    R->>E: embed(searchQuery)
    E-->>R: vecteur
    R->>C: query(vector, filter, nResults)
    C-->>R: chunks + distances
    R->>R: Filtre selon MAX_DISTANCE et construit le contexte
    R->>G: generate(prefix, history, question, image?)
    G-->>R: texte normalisé
    R->>R: UsageMeter + règlement du budget
    R-->>A: answered / insufficient_context
    A-->>S: résultat RAG
    alt réponse exploitable
        S->>S: Sauvegarde message IA
        S-->>U: Réponse IA
    else contexte insuffisant
        S->>S: Sauvegarde clarification ou suggestion d’escalade
        S-->>U: Propose le support humain
    end

```

### Construction du contexte de récupération

Le navigateur ne décide pas directement du scope RAG. Le backend dérive les `retrievalContexts` à partir des produits possédés par l'utilisateur. Les filtres peuvent inclure le jeu, le scope, l'audience et d'autres métadonnées documentaires.

L'historique envoyé à l'IA contient uniquement les tours USER et AI, dans une fenêtre bornée. L'image, lorsqu'elle existe, est attachée uniquement au tour courant.

## 4. Décision de réponse ou d’escalade

```mermaid
flowchart TD
    Q[Requête utilisateur] --> SEARCH[Recherche Chroma]
    SEARCH --> REL{Assez de chunks pertinents ?}
    REL -->|Non et aucune image| IC[insufficient_context]
    REL -->|Oui| CTX[Construire le contexte]
    REL -->|Image présente| CTX
    CTX --> GEN[Génération LLM]
    GEN --> OUT{Réponse vide ou marqueur unsupported ?}
    OUT -->|Oui| IC
    OUT -->|Non| ANS[Retourner answer + confidence]
    IC --> SUG[SupportService clarifie puis propose l’escalade]
    ANS --> SAVE[Sauvegarder le message IA]
    SUG --> HUMAN[Utilisateur peut escalader vers un humain]

```

## Contrôle des coûts et garde-fous

Chaque opération protégée du serveur IA passe par une réservation de budget avant l'appel au modèle. Un `UsageMeter` accumule ensuite l'usage réellement observé et permet de régler la réservation dans un bloc `finally`, même si l'opération échoue.

- Plafonds d'entrée, de sortie et de taille de recherche.
- Timeouts côté NestJS et côté providers.
- Tarification associée au provider/modèle réellement utilisé.
- Refus des modèles non tarifés ou inconnus.
- Endpoint de santé séparant l'état du provider de génération, de l'embedding et de Chroma.

## Fichiers principaux

- `uniksim-back-end/src/service/support.service.ts`
- `uniksim-back-end/src/service/ai.service.ts`
- `uniksim-back-end/src/node.js/server/ai/server.js`
- `uniksim-back-end/src/embedding/ingest.js`
- `server/ai/provider/*` pour les providers de génération, embedding, tokenizer et pricing.

## Points d’attention

- Changer uniquement le provider de génération ne nécessite pas de réindexer Chroma.
- Changer le modèle d'embedding modifie l'espace vectoriel et implique normalement une réindexation.
- Les objets SDK spécifiques à un fournisseur ne doivent pas sortir de son provider.
- La réponse IA ne doit être considérée valide que si le contexte est suffisamment pertinent et que le provider retourne une réponse supportée.

## Frontend et expérience utilisateur

Le frontend ne connaît pas directement Chroma, les embeddings ni les règles internes de retrieval. Il envoie le message utilisateur au backend et affiche le résultat normalisé retourné par le système de support.

```mermaid
flowchart LR
    UI[UI Support / Chat]
    HTTP[Service frontend HTTP]
    SS[SupportService]
    AI[Pipeline RAG]
    SOCK[SupportSocketService]
    STATE[Etat local / conversation]

    UI -->|message + attachment| HTTP
    HTTP --> SS
    SS --> AI
    AI --> SS
    SS -->|persistance| DB[(MySQL)]
    SS -->|MESSAGE_CREATED| SOCK
    SOCK --> STATE
    STATE --> UI

    SS -->|insufficient_context| ESC[Clarification puis suggestion d’escalade]
    ESC --> UI

```

### Responsabilités du frontend

- collecter le texte saisi et la pièce jointe éventuelle;
- envoyer l'action utilisateur au backend;
- afficher les messages USER, AI, SYSTEM et ADMIN selon leur type;
- afficher les clarifications et, au seuil configuré, la suggestion de support humain décidées par le backend;
- mettre à jour l'interface à partir des événements temps réel plutôt que d'exécuter lui-même la logique RAG.

### Ce que le frontend ne décide pas

Le navigateur ne choisit ni les documents recherchés ni le scope documentaire. Les `retrievalContexts` sont construits côté serveur à partir des droits et produits de l'utilisateur. Cela évite qu'un client modifie directement le jeu, l'audience ou le scope envoyés à Chroma.

### Historique et pièces jointes

L'historique RAG est reconstruit côté backend à partir des messages persistés. Le frontend n'a donc pas à fabriquer le prompt conversationnel complet. Lorsqu'une image est jointe, elle est validée et chargée côté backend avant d'être transmise au serveur IA, et n'est attachée qu'au tour utilisateur courant.

### Réponse IA vs expérience de support

Pour le frontend, le RAG produit des messages IA dans la conversation de support. Une réponse exploitable apparaît comme un message AI. Si le contexte est insuffisant, le backend sauvegarde d’abord des demandes de clarification AI, puis une suggestion de support humain après deux clarifications consécutives. L’utilisateur peut alors demander l’escalade.

## État actuel du pipeline — 30 septembre 2026

`GeminiProvider` et `GeminiEmbeddingProvider` utilisent Vertex AI via `vertex_client.js`. Génération : `gemini-3.5-flash-lite` avec `THINKING_LEVEL=LOW`; embeddings : `gemini-embedding-001`. Chroma est un `CloudClient` avec collection `game`.

Le listener IA démarre sur `127.0.0.1:8106` avant l’initialisation des dépendances. NestJS attend ce listener, pas la disponibilité du modèle et de Chroma. `/ai/health` retourne 503 si une dépendance manque; les requêtes retentent son initialisation.

### Clarifications avant support humain

Le statut positif du contrat HTTP est `answered`; sans contexte, il est `insufficient_context`. `SupportService` compte les clarifications IA consécutives : les deux premières réponses sauvegardent `uniksim.support_ai_clarify`, puis la suivante sauvegarde `uniksim.support_suggest_escalation`. Ces messages ont le type AI. L’utilisateur demande ensuite l’escalade; le statut insuffisant ne crée pas automatiquement un ticket.

Un salut simple sans image reçoit une réponse locale sans embedding ni génération. Une image validée peut permettre la génération sans passage assez proche; le prompt interdit d’inventer des faits sur la plateforme. Pour le texte, le seuil est au moins un chunk de distance ≤ 0,5. La confidence est la moyenne de `clamp(1 - distance, 0, 1)`; elle indique la proximité documentaire, pas une probabilité de justesse.

### Usage, cache et réservation

Instructions et contexte précèdent l’historique et l’image courante pour permettre le cache implicite Gemini. Le cache de contexte explicite a été retiré. Le tokenizer normalise input, cachedInput, output et reasoning; le pricing facture le raisonnement comme sortie. La réservation utilise le plafond du modèle de 65 536 tokens facturables de sortie, et non les seules limites visibles de 4 000 tokens par réponse ou 256 par résumé.

`UsageMeter` conserve les coûts en nanodollars entiers puis les convertit en cents. L’usage absent, incohérent ou d’un tier non pris en charge reste estimé au plafond. Le `finally` règle la réservation; si la réconciliation échoue, la réservation durable est conservée. Version : `vertex-global-standard-2026-09-29`. Voir [Ajouter un nouveau provider IA](https://wiki.uniksim.com/books/web/page/ajouter-un-nouveau-provider-ia).

# Support temps réel

## Vue d’ensemble

Le support utilise HTTP pour valider et persister les conversations, messages et tickets; Socket.IO diffuse les changements après leur sauvegarde. Le refactoring du 30 septembre 2026 sépare le temps réel du compte de celui du support.

## Deux namespaces et un transport partagé

<table id="bkmrk-responsabilit%C3%A9-compt"><thead><tr><th>Responsabilité</th><th>Compte : /account</th><th>Support : /support</th></tr></thead><tbody><tr><td>Backend</td><td>`AccountGateway` + `PresenceService`</td><td>`SupportGateway` + `SupportService`</td></tr><tr><td>Frontend</td><td>`AccountSocketService`</td><td>`SupportSocketService`</td></tr><tr><td>Événements reçus</td><td>`user.status, user.presence, admin.status, notification.created`</td><td>`message.created, ticket.updated, typing`</td></tr><tr><td>Actions émises</td><td>`updateStatus, updateTelemetry, updateGamePresence`</td><td>`joinConversation, leaveConversation, typing, checkOnline`</td></tr></tbody></table>

Les services frontend utilisent `RealtimeSocket`, qui centralise l’authentification, les observables, la reconnexion et les acknowledgements. Les namespaces d’un même serveur partagent la connexion sous-jacente, mais leurs rooms sont indépendantes.

```mermaid
flowchart LR
UI[Interface] --> HTTP[API HTTP NestJS]
HTTP --> S[SupportService]
S --> DB[(MySQL)]
S --> E[EventEmitter]
E --> SG[SupportGateway /support]
SG --> SS[SupportSocketService]
SS --> UI
AS[AccountSocketService] <--> AG[AccountGateway /account]
AG --> P[PresenceService]
N[NotificationService] --> AG
AS --> UI
```

## Authentification, rooms et présence

Chaque gateway installe `socketAuthMiddleware(jwtService)` à l’initialisation du namespace. Le JWT est vérifié avant les handlers; le payload est placé dans `client.data.user`. Le token est accepté depuis `handshake.auth.token`, la query ou l’en-tête Authorization.

`AccountGateway` enregistre et retire les connexions dans `PresenceService`. Seuls les sockets du namespace compte comptent pour la présence. `SupportGateway` rejoint `user_<id>` et, pour les administrateurs, `admins`; il ne crée pas une seconde connexion de présence.

Pour `joinConversation`, un utilisateur doit posséder la conversation; les admins peuvent joindre les conversations de support. `typing` exige l’appartenance à `conversation_<id>` et ne vise que les autres sockets de cette room. `checkOnline` interroge `PresenceService`; un non-admin est limité aux admins assignés à ses tickets.

## Message et réponse IA

1. L’interface envoie le message et la pièce jointe par HTTP.
2. `SupportService` valide la conversation et la pièce jointe puis sauvegarde le message USER.
3. `MESSAGE_CREATED` est émis; le gateway mappe le message avec `SupportMapper.toMessageDto` et diffuse `message.created` vers sa conversation.
4. Dans une conversation non escaladée, le service construit l’historique, la langue et les droits documentaires puis appelle `AIService.queryRAG`. La réponse ou le message système est persisté et diffusé par le même chemin.

Voir [Pipeline RAG et système IA](https://wiki.uniksim.com/books/web/page/pipeline-rag-et-systeme-ia) pour les clarifications et l’escalade lorsque le contexte est insuffisant.

## Escalade et cycle de vie des tickets

L’escalade protège la transition `conversation.escalated: false → true` par une transaction atomique. Elle crée le ticket OPEN, sauvegarde un message SYSTEM, émet `MESSAGE_CREATED` et `TICKET_UPDATED`, puis demande un résumé asynchrone pour l’administration. Le premier admin qui répond peut devenir l’assigné.

```mermaid
stateDiagram-v2
[*] --> OPEN
OPEN --> IN_PROGRESS: assignTicket ou première réponse admin
OPEN --> RESOLVED: resolveTicket
IN_PROGRESS --> RESOLVED: resolveTicket
RESOLVED --> IN_PROGRESS: reopenTicket avec assigné
RESOLVED --> OPEN: reopenTicket sans assigné
```

## Lecture et notifications

Les marqueurs `lastUserReadAt / lastUserReadMessageId` et `lastAdminReadAt / lastAdminReadMessageId` sont indépendants. L’utilisateur compte les messages ADMIN non lus; l’admin compte les messages USER non lus. Pour `ticket.updated`, le gateway obtient deux vues via `getTicketUpdates` et envoie la vue utilisateur à sa room, la vue admin à `admins`.

Les notifications de compte suivent `NotificationService → AccountGateway → AccountSocketService`. Elles sont distinctes des mises à jour de ticket. Voir [Notifications et Push](https://wiki.uniksim.com/books/web/page/notifications-et-push).

## Reconnexion et état frontend

`SupportSocketService` conserve l’ID de conversation active et rejoint sa room à la reconnexion. `AccountSocketService` remet l’utilisateur en ligne, réémet la télémétrie si le consentement est accordé et restaure le jeu actif. Le retrait du consentement envoie une télémétrie nulle; quitter le jeu efface sa présence. Les composants support restent centrés sur les messages, tickets et leur état local.

`RealtimeSocket` encapsule `connect/disconnect`, `on`, `emit`, `emitWithAck` et `close`. L’HTTP charge l’état initial et persiste les actions; les événements synchronisent l’interface.

## Fichiers principaux

- Backend : `src/gateway/account.gateway.ts`, `support.gateway.ts`, `src/guards/socketAuth.middleware.ts`, `src/service/presence.service.ts`, `support.service.ts`.
- Angular : `service/realtime/realtime-socket.ts`, `service/account/account-socket.service.ts`, `service/support/support-socket.service.ts` et `support-state.service.ts`.
- Contrats : `Models/Presence.ts`, `Models/Notification.ts`, `Models/Support.ts`; constantes : `account.constants.ts`, `realtime.constants.ts`, `support.constants.ts`.

# Architecture générale

Vue d'ensemble du système Web Uniksim : frontend Angular, backend NestJS, flux principaux, responsabilités des couches et points d'entrée.

# Vue d’ensemble du système Web

## But de cette page

Cette page est la **carte d’entrée du système Web Uniksim**. Elle permet de comprendre rapidement quelles applications existent, comment elles communiquent, où sont stockées les données et dans quel chapitre chercher lorsqu’un problème survient.

## Carte globale du système

```mermaid
flowchart LR
    USER[Utilisateur] --> ANG[Frontend Angular]
    ADMIN[Administrateur] --> ANG

    ANG -->|HTTP| NEST[NestJS principal :3000]
    ANG <-->|Socket.IO| WS[SupportGateway /support]
    ANG <-->|Socket.IO| ACC[AccountGateway /account]
    ANG --> UNITY[Unity WebGL]

    UNITY -->|HTTP / heartbeat / données jeu| NEST

    NEST --> CTRL[Controllers]
    CTRL --> SVC[Services métier]
    SVC --> ORM[TypeORM]
    ORM --> MYSQL[(MySQL)]

    SVC --> REDIS[(Redis)]
    SVC --> BC[BrainCloud]
    SVC --> FB[Firebase / FCM]
    SVC --> MAIL[Mail]
    SVC --> AI[Serveur IA :8106]

    NEST --> ADMINEXP[Admin Server Express :8105]
    ADMINEXP --> BC
    ADMINEXP --> REDIS

    AI --> CHROMA[(Chroma / embeddings)]
    AI --> PROVIDER[Provider IA]

    NEST --> STATIC[Frontend Angular compilé]
    STATIC --> USER

```

## Les grandes briques

### Frontend Angular

Application principale côté navigateur dans `uniksimFrontEnd/`. Elle contient les pages utilisateur et admin, les composants UI, les services HTTP, l’authentification frontend, le support temps réel et l’intégration Unity.

### Backend NestJS

Serveur HTTP principal dans `uniksim-back-end/`. Le point d’entrée est `src/main.ts` et l’assemblage global se fait dans `src/app.module.ts`. Il expose les APIs utilisateur, jeu, administration, support, notifications, push, mail et IA.

### Admin Server Express

Serveur HTTP auxiliaire séparé dans `src/node.js/server/admin_server.js`, sur le port `8105`. Il sert principalement certaines opérations historiques/BrainCloud, Redis, copie de simulations et SSE.

### Serveur IA

NestJS attend l’ouverture du listener IA sur `127.0.0.1:8106`, puis démarre. L’initialisation des providers et de Chroma se poursuit en arrière-plan; leur indisponibilité n’empêche pas NestJS ni l’endpoint de santé de démarrer. Les requêtes retentent les dépendances manquantes. Le serveur IA contient des contrats, factories, providers, tokenizer, pricing, `UsageMeter` et `CostGuard` sous `src/node.js/server/ai/`. Gemini utilise maintenant Vertex AI, avec génération et embeddings sélectionnés indépendamment.

### Unity WebGL

Le jeu Unity est intégré au Web. Angular affiche le build WebGL et Unity communique avec le backend pour les versions, textes, données utilisateur, heartbeat, classements, images et crash logs.

### Persistance

- **MySQL + TypeORM** : utilisateurs, rôles, produits, support, installations FCM, etc.
- **Redis** : présence, sessions, notifications, rankings et autres données runtime.
- **BrainCloud** : plusieurs données historiques et fonctions liées aux simulations.
- **Chroma** : recherche vectorielle du système IA/RAG.

## Flux typique d’une requête Web

```mermaid
sequenceDiagram
    participant U as Utilisateur
    participant A as Angular
    participant C as Controller NestJS
    participant S as Service
    participant D as MySQL / Redis / BrainCloud

    U->>A: Action dans l’interface
    A->>C: Requête HTTP
    C->>C: Guard / validation
    C->>S: Appel métier
    S->>D: Lecture / écriture
    D-->>S: Résultat
    S-->>C: Données métier
    C-->>A: Réponse API
    A-->>U: Mise à jour de l’interface

```

## Flux temps réel

Deux namespaces Socket.IO séparent les responsabilités : `/account` porte présence, télémétrie consentie, jeu actif et notifications; `/support` porte messages, tickets et typing. Le middleware JWT est commun, les rooms sont propres à chaque namespace et le frontend partage `RealtimeSocket`. Seuls les sockets du compte sont enregistrés dans `PresenceService`. Voir [Support temps réel](https://wiki.uniksim.com/books/web/page/support-temps-reel) et [Notifications et Push](https://wiki.uniksim.com/books/web/page/notifications-et-push).

Toutes les notifications sont stockées dans une inbox Redis du compte, diffusées par `AccountGateway` puis poussées vers toutes ses installations FCM. Les notifications envoyées par le jeu passent par `GameNotificationService`, qui vérifie les membres de la simulation BrainCloud. Les subscriptions FCM par productCode ont été retirées.

## Build et hébergement

Le build Angular de production est généré dans `uniksim-back-end/src/front`, puis NestJS est buildé à son tour. Le backend sert ensuite le frontend compilé avec `ServeStaticModule`. L’instance de développement hébergée est `sim.dev.uniksim.com`. Voir **Build et déploiement Web**.

## Où chercher selon le problème

- **Écran, navigation ou composant** → chapitre Frontend Angular.
- **Endpoint, logique backend, auth** → Serveurs et API.
- **Donnée SQL ou Redis** → Base de données et persistance.
- **Constante, port, environnement** → Configuration, environnements et constantes.
- **Chat, WebSocket, RAG, provider IA** → Support et IA.
- **Unity, notifications, Firebase, services externes** → Intégrations et systèmes transversaux.
- **Déploiement / instance demo** → Build et déploiement Web.

## Points d’entrée essentiels

- `uniksimFrontEnd/src/main.ts`
- `uniksimFrontEnd/src/app/app.module.ts`
- `uniksim-back-end/src/main.ts`
- `uniksim-back-end/src/app.module.ts`
- `uniksim-back-end/src/app.controller.ts`
- `uniksim-back-end/src/database.providers.ts`
- `uniksim-back-end/src/node.js/server/constantsVariable.js`
- `uniksim-back-end/src/node.js/server/admin_server.js`
- `uniksim-back-end/src/node.js/server/ai/`

# Structure des projets et dossiers

## Objectif

Cette page indique **où chercher dans le code** selon le type de changement ou de bug. Elle ne remplace pas les pages détaillées des sous-systèmes.

## Vue des deux projets principaux

```mermaid
flowchart TD
    ROOT[uniksimweb] --> FE[uniksimFrontEnd]
    ROOT --> BE[uniksim-back-end]

    FE --> FEA[src/app]
    FEA --> P[Pages]
    FEA --> C[Components]
    FEA --> POP[Popup]
    FEA --> FS[service]
    FEA --> FM[Models]

    BE --> BES[src]
    BES --> CTRL[app.controller.ts]
    BES --> MOD[app.module.ts]
    BES --> SV[service]
    BES --> ENT[entities]
    BES --> GW[gateway]
    BES --> G[guards]
    BES --> NODE[node.js/server]
    BES --> EMB[embedding]

```

## Frontend : uniksimFrontEnd

- `src/app/Pages/` : écrans complets et routes principales.
- `src/app/Components/` : composants réutilisables.
- `src/app/Popup/` : popups et dialogues.
- `src/app/service/` : logique frontend partagée, accès API, auth, support, notifications, présence, etc.
- `src/app/Models/` : modèles TypeScript.
- `src/app/constants/` : constantes frontend.
- `src/assets/` : ressources statiques, incluant le build Unity WebGL.
- `src/environments/environment.ts` : URLs/backend disponibles côté Angular.
- `angular.json` : build Angular et destination du build production.

## Backend : uniksim-back-end

- `src/main.ts` : bootstrap NestJS.
- `src/app.module.ts` : enregistrement global des modules, contrôleurs, services et intégrations.
- `src/app.controller.ts` : contrôleurs HTTP principaux.
- `src/service/` : logique métier.
- `src/entities/` : entités TypeORM.
- `src/gateway/` : WebSockets/Socket.IO.
- `src/guards/` : autorisation/authentification backend.
- `src/mapper/` : conversion entre données internes et réponses API.
- `src/dto/` : DTOs et contrats d’entrée/sortie.
- `src/node.js/server/` : couche historique/auxiliaire : BrainCloud, constantes, Admin Server, IA, Redis, etc.
- `src/embedding/` : ingestion et documentation destinée au RAG.
- `src/migrations/` : changements de schéma/versionnement DB lorsque utilisés.
- `src/front/` : **frontend Angular compilé**; ne pas modifier manuellement.

## Où commencer selon le besoin

- Nouvelle page Angular → `Pages/` + routing dans `app.module.ts`.
- Nouveau composant réutilisable → `Components/`.
- Nouvel appel API → service Angular approprié puis controller/service NestJS.
- Nouvelle donnée SQL → `entities/`, service/repository et schéma DB.
- Temps réel → `gateway/` côté backend et service Socket.IO côté frontend.
- Comportement IA → `node.js/server/ai/`, `embedding/` et services support concernés.
- Paramètre global → `constantsVariable.js` ou fichier d’environnement.

## Règle pratique

Avant d’ajouter un nouveau fichier ou une nouvelle abstraction, vérifier si le comportement appartient déjà à un dossier/service existant. Le projet contient plusieurs couches historiques; dupliquer une responsabilité peut rendre les flux beaucoup plus difficiles à suivre.

## Organisation des sous-systèmes

- Backend : `gateway/account.gateway.ts` pour le compte, `gateway/support.gateway.ts` pour le support, `guards/socketAuth.middleware.ts` pour leur authentification commune.
- Notifications : `service/notification.service.ts` est le pipeline générique; `service/game-notification.service.ts` valide le destinataire du jeu; `dto/notification.dto.ts` définit l’enveloppe.
- Angular : `service/realtime/` pour le transport, `service/account/` pour le temps réel du compte, `service/support/` pour les conversations et tickets; contrats séparés dans `Models/Notification.ts` et `Models/Presence.ts`.
- IA : `node.js/server/ai/contract/`, `factory/`, `guard/`, `usage/` et `provider/gemini/`. Le SDK Vertex et son adaptation restent dans le provider.
- Tests backend : `test/ai/` et `test/notification/`; configuration partagée `test/jest.config.cjs`, configuration IA `test/jest.ai.config.cjs`. Exécuter `npm test -- --runInBand` ou `npm run test:ai` depuis le backend.

# Frontières entre code moderne et legacy

## Pourquoi cette page existe

Le projet Web combine une architecture NestJS/Angular moderne avec une couche plus ancienne sous `src/node.js/server/`. Les deux sont encore actives. Comprendre cette frontière évite de réécrire une fonctionnalité déjà existante ou de modifier la mauvaise couche.

## Carte simplifiée

```mermaid
flowchart LR
    ANG[Angular] --> NEST[NestJS moderne]

    NEST --> CTRL[Controllers]
    CTRL --> SVC[Services TypeScript]
    SVC --> ORM[TypeORM / MySQL]
    SVC --> REDIS[RedisService]

    SVC --> LEGACY[src/node.js/server]
    LEGACY --> BC[BrainCloud]
    LEGACY --> REDIS
    LEGACY --> ADMIN[Admin Server Express]
    LEGACY --> AI[Serveur IA]

```

## Couche moderne

La majorité du nouveau code backend devrait naturellement passer par :

- `app.controller.ts` pour les endpoints;
- `service/*.service.ts` pour la logique métier;
- `entities/` et TypeORM pour MySQL;
- `guards/` pour l’autorisation;
- `gateway/` pour le temps réel.

## Couche historique / auxiliaire

`src/node.js/server/` contient encore plusieurs responsabilités importantes :

- `server.js` : fonctions historiques de jeu, présence, rankings, images, etc.;
- `backend_braincloud.js` : intégration BrainCloud;
- `admin_server.js` : serveur Express admin séparé;
- `constantsVariable.js` : configuration globale et constantes;
- `ai/` : serveur IA et providers.

## Quand utiliser quelle couche

```mermaid
flowchart TD
    NEW[Nouveau changement backend] --> EXIST{Fonction existante déjà dans node.js/server ?}
    EXIST -- Oui --> CONTRACT{Peut-on garder le contrat et l'encapsuler ?}
    CONTRACT -- Oui --> WRAP[Appeler depuis un service NestJS]
    CONTRACT -- Non --> MIGRATE[Planifier migration explicite]
    EXIST -- Non --> MODERN[Implémenter dans Controller + Service NestJS]

    MODERN --> DATA{Persistance ?}
    DATA -- SQL --> ORM[TypeORM]
    DATA -- Runtime --> REDIS[RedisService]

```

## Règle générale

Pour une nouvelle fonctionnalité, privilégier NestJS et les services TypeScript. Ne déplacer du code historique que lorsqu’il y a une raison claire : simplification, suppression d’une dépendance legacy ou correction d’un problème architectural. Une migration opportuniste au milieu d’une feature augmente le risque.

## Signaux qu’on touche du legacy

- appel direct à `backend_braincloud.js`;
- fonction exportée depuis `server.js`;
- utilisation du serveur Express admin;
- globals comme `NodeJsServer`, `NodeJsUtils` ou `NodeJsBackendBraincloud` initialisés dans `database.providers.ts`.

## Avant de refactorer

- Identifier tous les appels entrants vers la fonction legacy.
- Vérifier les effets Redis, BrainCloud et fichiers locaux.
- Conserver le contrat API existant si possible.
- Séparer migration et changement fonctionnel lorsqu’ils sont suffisamment gros.

## Frontière des notifications après refactoring

Les anciennes fonctions d’inbox/notification ont été retirées de `server.js`. La responsabilité appartient à `NotificationService` (stockage Redis, événement du compte et push) et à `GameNotificationService` (autorisation BrainCloud et résolution profil jeu → compte). Ne pas réintroduire une seconde inbox dans la couche historique. `AccountGateway` diffuse les notifications; `SupportGateway` conserve les conversations et tickets.

# Ajouter une fonctionnalité Web de bout en bout

## Objectif

Cette page donne un chemin pratique pour ajouter une fonctionnalité Web sans oublier une couche. Le principe est de suivre le flux Angular → API → service → données → retour UI.

## Flux type

```mermaid
flowchart LR
    UI[Page / Component Angular] --> FES[Service Angular]
    FES --> AUTH[AuthInterceptor]
    AUTH --> CTRL[Controller NestJS]
    CTRL --> GUARD[Guard]
    GUARD --> BES[Service backend]
    BES --> DATA{Données}
    DATA --> ORM[TypeORM / MySQL]
    DATA --> REDIS[Redis]
    DATA --> BC[BrainCloud]
    BES --> CTRL
    CTRL --> FES
    FES --> UI

```

## Étapes

1. Définir l’action utilisateur, les données entrantes/sortantes, le niveau d’accès et le type de persistance.
2. Côté Angular, placer l’écran dans `Pages/` ou le composant dans `Components/`, puis passer par un service Angular pour les appels backend.
3. Ajouter ou réutiliser la route dans `app.module.ts` et appliquer le guard frontend adapté.
4. Côté backend, ajouter l’endpoint au controller logique existant. Garder le controller mince.
5. Placer la logique métier dans `src/service/`.
6. Choisir le stockage : TypeORM/MySQL pour le relationnel persistant, Redis pour le runtime/temporaire, BrainCloud pour les données historiques de simulation déjà gérées là.
7. Ajouter Socket.IO/EventEmitter seulement si la mise à jour doit être temps réel.
8. Appliquer le guard backend approprié et valider les IDs et permissions côté serveur.
9. Centraliser les paramètres dans `constantsVariable.js` ou les fichiers `.env`.
10. Tester le cas nominal, les entrées invalides, les accès interdits et les erreurs de dépendances.

## Choisir le stockage

```mermaid
flowchart TD
    D[Besoin de stockage] --> P{Persistant relationnel ?}
    P -- Oui --> SQL[Entity TypeORM + MySQL]
    P -- Non --> RT{Temporaire / temps réel ?}
    RT -- Oui --> REDIS[RedisService]
    RT -- Non --> OLD{Déjà géré dans BrainCloud ?}
    OLD -- Oui --> BC[BrainCloud]
    OLD -- Non --> REVIEW[Revoir le modèle avant d'ajouter un stockage]

```

## Checklist rapide

- UI dans le bon dossier.
- Service Angular réutilisé ou créé au bon endroit.
- Route et guards corrects.
- Controller mince.
- Logique dans un service backend.
- Stockage choisi selon le type de donnée.
- Temps réel ajouté seulement si nécessaire.
- Cas d’erreur et permissions testés.
- Configuration centralisée.
- Build/deploy vérifié.
- Documentation mise à jour si l’architecture change.

# Serveurs et API

Documentation des serveurs, API, authentification, accès aux données, configuration des environnements et services backend.

# Serveur principal NestJS

## Rôle

Le backend Web principal est une application NestJS située dans `uniksim-back-end/`. Elle centralise les API utilisateur, jeu, administration, support, notifications, push, mail et IA.

## Démarrage

Le point d’entrée est `src/main.ts`.

- Attend `aiServerReady` avant de créer l’application NestJS.
- Crée l’application à partir de `AppModule`.
- Active CORS pour le frontend local sur `http://localhost:4200`.
- Autorise les payloads JSON et URL-encoded jusqu’à 50 MB.
- Ajoute l’en-tête HSTS.
- Écoute sur le port `3000`.

## Assemblage du backend

`src/app.module.ts` branche les principaux sous-systèmes :

- TypeORM et les entités métier.
- JWT global avec expiration de 4 heures.
- i18n.
- fichiers statiques frontend.
- HTTP externe.
- services utilisateurs, jeu, administration, IA, support, Redis, notifications, Firebase et présence.
- gateway WebSocket du support.

## Contrôleurs importants

- `LoginController` : connexion et création de compte.
- `UserController` : fonctionnalités utilisateur connecté.
- `GameController` : endpoints consommés par le jeu/WebGL.
- `AdminController`, `AdminUserController`, `AdminPresenceController` : administration.
- `SupportController`, `SupportAdminController` : support.
- `NotificationController`, `PushController` : notifications et push.

# Administration : API NestJS et Admin Server Express

## Vue d’ensemble

L’administration backend d’Uniksim repose sur **deux couches distinctes** qu’il ne faut pas confondre :

1. **les routes d’administration de l’API NestJS principale**, protégées par des guards et reliées aux services backend;
2. **un serveur Express d’administration séparé** dans `uniksim-back-end/src/node.js/server/admin_server.js`, qui écoute localement sur le port `8105` et gère surtout des opérations historiques/BrainCloud et certains flux SSE.

## Architecture backend d’administration

```mermaid
flowchart LR
    CLIENT[Clients Web / outils internes] --> NEST[NestJS principal]
    CLIENT --> EXPRESS[Admin Server Express :8105]

    NEST --> AC[AdminController]
    NEST --> AUC[AdminUserController]
    NEST --> APC[AdminPresenceController]
    NEST --> SAC[SupportAdminController]

    AC --> AS[AdminService]
    AUC --> AUS[AdminUserService]
    APC --> PS[PresenceService]

    AS --> DB[(MySQL / TypeORM)]
    AUS --> DB
    PS --> REDIS[(Redis)]

    EXPRESS --> BC[BrainCloud]
    EXPRESS --> REDIS
    EXPRESS --> SSE[SSE / copie de simulations]

```

## 1. Administration dans l’API NestJS

Les contrôleurs d’administration sont regroupés dans `uniksim-back-end/src/app.controller.ts` et enregistrés dans `AppModule`.

- `AdminUserController` sous `/admin` : récupération et gestion d’informations utilisateurs.
- `AdminPresenceController` sous `/admin/presence` : présence en ligne, état de jeu et télémétrie.
- `AdminController` : autres opérations administratives.
- `SupportAdminController` : fonctions administratives du support.

La logique métier correspondante se trouve notamment dans `src/service/admin.service.ts`, `src/service/adminUser.service.ts` et `src/service/presence.service.ts`.

## 2. Admin Server Express séparé

Le fichier `src/node.js/server/admin_server.js` démarre un serveur Express distinct sur `ConstantsInUse.ADMIN_SERVER_PORT`, actuellement `8105`. Son URL locale de référence est définie par `ADMIN_SERVER_URL` dans `constantsVariable.js`.

Ce serveur est utilisé notamment pour :

- `POST /admin/adminCommand` : commandes d’administration BrainCloud telles que lecture de documents, récupération de simulations, copie de simulation et suppression d’un utilisateur d’une simulation;
- `POST /redisBulkCommands` : commandes Redis groupées;
- `GET /getActiveSimulations/...` : récupération des simulations actives;
- `GET /copySimNotification` : progression d’une copie de simulation via SSE;
- surveillance de certains jobs BrainCloud et relance lorsqu’ils disparaissent.

## Flux d’une commande Admin Server

```mermaid
sequenceDiagram
    participant C as Client / outil admin
    participant E as Admin Server Express
    participant B as BrainCloud
    participant R as Redis
    participant S as Flux SSE

    C->>E: Requête admin
    alt Commande BrainCloud
        E->>B: Exécute la commande
        B-->>E: Résultat
    else Commande Redis
        E->>R: redisBulkCommands(...)
        R-->>E: Résultat
    else Copie de simulation
        E->>B: Copie données / simulation
        E-->>S: Progression
        S-->>C: Événements SSE
    end
    E-->>C: Réponse

```

## Sécurité backend

Les routes NestJS utilisent notamment `AuthGuardAdmin` et `AuthGuardAdminUser`. Toute modification d’une route d’administration doit vérifier le guard attendu et le rôle autorisé.

## Fichiers principaux

- `uniksim-back-end/src/app.controller.ts`
- `uniksim-back-end/src/app.module.ts`
- `uniksim-back-end/src/node.js/server/admin_server.js`
- `uniksim-back-end/src/node.js/server/constantsVariable.js`
- `uniksim-back-end/src/service/admin.service.ts`
- `uniksim-back-end/src/service/adminUser.service.ts`
- `uniksim-back-end/src/service/presence.service.ts`

# Authentification et guards

## Vue d’ensemble

L’authentification combine JWT côté backend et des guards côté backend et frontend.

## Backend

- JWT configuré globalement dans `src/app.module.ts`.
- Secret provenant de `JwtConstants.secretJwt`.
- Durée de validité configurée à 4 heures.
- `AuthGuardUser` protège les endpoints utilisateur.
- `AuthGuardGame` protège les endpoints consommés par le jeu.
- `AuthGuardAdmin` et `AuthGuardAdminUser` protègent les fonctions administratives.

## Frontend

Les guards Angular sont dans `uniksimFrontEnd/src/app/service/auth/`. Les routes sont protégées directement dans `app.module.ts`.

`AuthInterceptorService` est enregistré comme `HTTP_INTERCEPTORS` afin d’appliquer la logique d’authentification aux appels HTTP.

## Connexion

`LoginController` expose notamment `signIn`, `signUp` et le login spécial Chenelière. La logique métier correspondante se trouve dans `src/service/login.service.ts`.

## Socket.IO et notifications du jeu

`socketAuthMiddleware` est installé sur `/account` et `/support`. Il vérifie le JWT avant tout handler puis stocke le payload dans `client.data.user`. Le token peut venir de `handshake.auth.token`, de la query ou de Authorization. Angular envoie `auth: { token }` via le transport commun `RealtimeSocket`.

Les rooms support sont soumises à l’appartenance à la conversation; `typing` exige d’avoir rejoint la room et `checkOnline` limite les non-admins à leurs admins assignés. Les sockets de présence appartiennent au namespace compte.

`POST /saveNotification` utilise `AuthGuardUser`. `GameNotificationService` vérifie le profil actif destinataire et les membres de la simulation BrainCloud; les types réservés au serveur sont refusés. Les routes d’inbox et d’installations FCM dérivent le compte de `request.user.sub`.

# Configuration, environnements et constantes

## Vue d’ensemble

La configuration backend est principalement répartie entre les fichiers d’environnement et `uniksim-back-end/src/node.js/server/constantsVariable.js`. Ce fichier centralise de nombreuses valeurs utilisées par les serveurs, les intégrations et les règles métier.

**Ne jamais recopier de secrets dans le wiki.** Le fichier contient des clés, mots de passe et credentials qui doivent rester dans le code ou une configuration sécurisée et ne doivent pas être documentés en clair.

## Fichiers d’environnement

- `dev.env` : environnement de développement.
- `dev2.env` : deuxième environnement de développement.
- `demo.env` : environnement demo.
- `live.env` : environnement live.

Les scripts de démarrage du backend sélectionnent explicitement l’un de ces fichiers via `node --env-file ... dist/main`.

## constantsVariable.js

Le fichier `src/node.js/server/constantsVariable.js` sert de registre central pour plusieurs familles de constantes.

- `SERVER_INSTANCE` : live, dev, demo, dev2 et demoLive.
- `HOSTNAME`, `PORTS`, `USERNAME` : paramètres d’infrastructure.
- `SITE_URL_COMPLET` : URLs des instances Web.
- `ConstantsInUse` : valeurs effectivement utilisées par le processus courant.
- `ADMIN_SERVER_URL` / `AI_SERVER_URL` : services locaux auxiliaires.
- `ROLES_STRING` / `ROLES_NUMBER` : mapping des rôles.
- `SIMULATION` : identifiants des jeux.
- `AI_CONFIG` : provider, modèles, limites, timeouts et paramètres RAG.
- `SUPPORT_CONFIG` : uploads, limites de messages, événements et comportement IA du support.
- `NOTIFICATION_CONFIG` : rétention Redis et événements de notification.
- `FIREBASE_CONFIG` : paramètres techniques Firebase/FCM.

## ConstantsInUse

`ConstantsInUse` agit comme configuration runtime commune. Elle contient notamment la base ciblée, le host SQL, le port SQL, le serveur courant, l’URL du site, la version WebGL locale et les ports des serveurs auxiliaires.

Lorsqu’un bug apparaît uniquement en dev/demo/live, ce bloc est un des premiers endroits à vérifier avec le fichier `.env` correspondant.

## Frontend

Côté Angular, `uniksimFrontEnd/src/environments/environment.ts` définit notamment les URLs de serveur utilisables et le backend attendu.

## Points d’attention

- Ne pas ajouter une nouvelle constante “temporaire” sans vérifier si elle existe déjà dans une famille logique.
- Une modification de port ou d’URL peut affecter plusieurs processus : NestJS, Admin Server, IA, Angular ou Redis.
- Les rôles numériques doivent rester cohérents avec les données en base.
- Les valeurs sensibles ne doivent jamais être copiées dans la documentation.

## Configuration IA et temps réel actuelle

Au 30 septembre 2026 : `GOOGLE_CLOUD_PROJECT` est requis pour Vertex AI; `GOOGLE_CLOUD_LOCATION` vaut `global` par défaut et cette location est imposée par la politique tarifaire actuelle. L’authentification utilise les credentials Google par défaut de l’environnement. Chroma Cloud utilise les variables `CHROMA_API_KEY`, `CHROMA_TENANT` et `CHROMA_DATABASE`; la collection est `game`. Ne pas recopier leurs valeurs ici.

`AI_MODELS` configure `gemini-3.5-flash-lite` et `gemini-embedding-001`. `AI_PRICE_VERSIONS` référence `vertex-global-standard-2026-09-29`; `THINKING_LEVEL` vaut LOW. Le provider de génération et celui d’embedding restent indépendants. Le serveur IA écoute sur loopback; son token interne protège les opérations query/summary.

`NOTIFICATION_CONFIG` fixe le suffixe `_notifications`, la taille maximale de l’inbox (100), sa rétention (10 519 200 secondes), les types serveur réservés et la taille du payload client (2 048 caractères). Les constantes Angular sont séparées dans `realtime.constants.ts` (transport), `account.constants.ts` (activité du compte) et `support.constants.ts` (support).

# Base de données et persistance

## Vue d’ensemble

Le backend utilise principalement **MySQL via TypeORM** pour les données relationnelles, et **Redis** pour plusieurs données temporaires ou temps réel.

## Architecture de persistance

```mermaid
flowchart TD
    API[NestJS Controllers] --> SERVICES[Services métier]
    SERVICES --> ORM[TypeORM]
    ORM --> MYSQL[(MySQL)]

    SERVICES --> REDIS[RedisService]
    REDIS --> CACHE[(Redis)]

    SERVICES --> BC[BrainCloud]

    MYSQL --> E1[Users / rôles]
    MYSQL --> E2[Produits / codes]
    MYSQL --> E3[Support]
    MYSQL --> E4[FCM installations]

    CACHE --> R1[Présence]
    CACHE --> R2[Sessions]
    CACHE --> R3[Notifications]
    CACHE --> R4[Rankings / données temps réel]

```

## Configuration TypeORM

Le point central est `uniksim-back-end/src/database.providers.ts`.

La connexion est créée avec `TypeOrmModule.forRoot(...)` et utilise :

- `ConstantsInUse.HOSTNAME`
- `ConstantsInUse.PORTS`
- `ConstantsInUse.USERNAME`
- `ConstantsInUse.PASSWORD_DATABASE`
- `ConstantsInUse.PROVIDERS`

Le backend est configuré avec `synchronize: false`. Les changements de schéma ne doivent donc pas être supposés automatiques.

## Entités principales

Les entités TypeORM sont dans `uniksim-back-end/src/entities/`. Parmi les principales :

- `User`, `Role`, `RoleUser`
- `Product`, `ProductsCode`, `ProductsResources`, `Resources`
- `Period`, `Constant`
- `SupportConversation`, `SupportTicket`, `SupportMessage`
- `UserFcmToken`

## Redis

Redis n’est pas seulement un cache. Il est utilisé pour plusieurs fonctions runtime importantes, notamment :

- présence et heartbeats;
- sessions de jeu;
- notifications persistées temporairement;
- rankings et certaines données de simulation;
- communication de certains services historiques.

## Choisir le bon stockage

```mermaid
flowchart LR
    CHANGE[Besoin métier] --> ENTITY{Donnée relationnelle ?}
    ENTITY -- Oui --> MODEL[Entity TypeORM]
    MODEL --> ORM[Repository / Service]
    ORM --> SCHEMA[Vérifier schéma SQL / migration]

    ENTITY -- Non --> RUNTIME{Temporaire ou temps réel ?}
    RUNTIME -- Oui --> REDIS[RedisService]
    RUNTIME -- Non --> OTHER[Vérifier BrainCloud / stockage existant]

```

## Points d’attention

- Ne pas activer `synchronize: true` sur un environnement partagé pour contourner un changement de schéma.
- Vérifier les relations d’entités avant de supprimer ou renommer une colonne.
- Redis contient des données applicatives importantes : un flush peut affecter sessions, présence ou notifications.
- Avant d’ajouter un nouveau stockage, vérifier si le système utilise déjà MySQL, Redis ou BrainCloud pour ce type de donnée.

## Évolution de la persistance des notifications

Au 30 septembre 2026, les entités enregistrées dans `database.providers.ts` comprennent `UserFcmToken`, sans modèle de subscription par produit. Une installation appartient au compte; les push ciblent toutes ses installations. L’inbox Redis `user_<id>_notifications` est bornée à 100 entrées; son TTL de 10 519 200 secondes est renouvelé à chaque insertion. `NotificationService` possède maintenant la logique d’inbox; les anciennes fonctions de notification dans `server.js` ont été retirées. Voir [Notifications et Push](https://wiki.uniksim.com/books/web/page/notifications-et-push).

# Build et déploiement Web

## Vue d’ensemble

Le frontend Angular et le backend NestJS sont déployés ensemble. Le build Angular de production écrit directement dans le backend, puis le backend est compilé et démarré avec l’environnement voulu.

## Pipeline de build

```mermaid
flowchart TD
    A[uniksimFrontEnd] -->|npm run build| B[uniksim-back-end/src/front]
    B -->|npm run build dans le backend| C[uniksim-back-end/dist]
    C -->|npm run start:demo| D[Node + demo.env]
    D --> E[sim.dev.uniksim.com]

```

## Pourquoi le frontend apparaît dans le backend

Dans `uniksimFrontEnd/angular.json`, la configuration de production utilise :

`outputPath: ../uniksim-back-end/src/front`

Le dossier `src/front` contient donc le **résultat compilé d’Angular**. Ce n’est pas un dossier frontend à modifier manuellement.

Lors du build NestJS, ces fichiers sont ensuite disponibles dans le build backend, et `ServeStaticModule` les sert au navigateur.

## Serveur de développement hébergé

L’instance de développement est accessible via `sim.dev.uniksim.com` sur l’infrastructure DigitalOcean.

Le workflow serveur utilisé actuellement est :

1. Se connecter au serveur DigitalOcean.
2. Passer sur l’utilisateur `forge` avec `sudo -u forge` ou la commande équivalente utilisée sur le serveur.
3. Aller dans le dossier du site avec `cd sim.dev.uniksim.com`.
4. Mettre le code à jour.
5. Builder le frontend Angular avec `npm run build` dans `uniksimFrontEnd`.
6. Builder le backend NestJS avec `npm run build` dans `uniksim-back-end`.
7. Démarrer le backend avec `npm run start:demo`.

## Ordre de build

```mermaid
sequenceDiagram
    participant D as Développeur
    participant F as Angular
    participant B as Backend NestJS
    participant N as Node demo
    participant W as sim.dev.uniksim.com

    D->>F: npm run build
    F-->>B: Génère src/front
    D->>B: npm run build
    B-->>N: Génère dist
    D->>N: npm run start:demo
    N->>N: Charge demo.env
    N-->>W: Sert API + frontend compilé

```

## Scripts backend disponibles

- `npm run build` : compile NestJS.
- `npm run start:dev` : démarre `dist/main` avec `dev.env`.
- `npm run start:dev2` : démarre avec `dev2.env`.
- `npm run start:demo` : démarre avec `demo.env`.
- `npm run start:live` : démarre avec `live.env`.

## Points d’attention

- Le frontend doit être buildé **avant** le backend si on veut embarquer la nouvelle version Angular dans le build backend.
- Après une modification uniquement backend, le build Angular n’est pas toujours nécessaire.
- Après une modification frontend, vérifier que les fichiers générés sont présents dans `uniksim-back-end/src/front` avant le build backend.
- Vérifier l’environnement utilisé avant de lancer le serveur : `demo`, `dev`, `dev2` ou `live`.

# Conventions de sécurité Web

## But

Cette page résume les mécanismes de sécurité réellement présents dans le projet. Elle ne remplace pas un audit de sécurité; elle sert de guide pour éviter de contourner les protections existantes lorsqu’on ajoute une feature.

## Authentification et autorisation

Le backend utilise des JWT et plusieurs guards spécialisés :

- `AuthGuardUser` : utilisateur authentifié;
- `AuthGuardAdmin` : rôle admin;
- `AuthGuardAdminUser` : admin ou admin\_user;
- `AuthGuardGame` : accès utilisé par les appels du jeu.

Les tokens peuvent être lus depuis l’en-tête `Authorization: Bearer ...` ou, selon le flux, depuis le cookie `token`. Les guards backend restent la source d’autorité; les guards Angular servent surtout à contrôler la navigation.

## Flux d’autorisation

```mermaid
sequenceDiagram
    participant C as Client
    participant G as Guard NestJS
    participant J as JwtService
    participant E as Endpoint

    C->>G: Requête + token
    G->>J: Vérifie signature / expiration
    J-->>G: Payload
    G->>G: Vérifie rôle si nécessaire
    alt Autorisé
        G->>E: Continue
        E-->>C: Réponse
    else Refusé
        G-->>C: 401 Unauthorized
    end

```

## Configuration HTTP

Dans `src/main.ts` :

- CORS est configuré avec credentials;
- les requêtes JSON et URL-encoded ont une limite de taille;
- l’en-tête HSTS `Strict-Transport-Security` est ajouté;
- le serveur principal écoute sur le port `3000`.

## Uploads du support

`SupportAttachmentService` applique plusieurs contrôles avant de stocker ou servir une image :

- validation du contenu binaire réel plutôt que confiance dans le MIME envoyé par le navigateur;
- types d’image autorisés limités;
- normalisation en WebP;
- limite de dimensions et de taille;
- nom de fichier aléatoire et normalisé;
- protection contre les chemins arbitraires via `path.basename` et validation du format;
- vérification que la pièce jointe appartient à la conversation/utilisateur demandé;
- quotas de stockage utilisateur et global;
- nettoyage des uploads orphelins.

## Sécurité des fichiers

```mermaid
flowchart TD
    U[Upload] --> BIN[Valider signature binaire]
    BIN --> SIZE[Vérifier dimensions / taille]
    SIZE --> NORMAL[Normaliser en WebP]
    NORMAL --> NAME[Générer nom aléatoire]
    NAME --> QUOTA[Vérifier quotas]
    QUOTA --> SAVE[Écrire avec création exclusive]

    READ[Lecture] --> PATH[Vérifier nom / chemin]
    PATH --> OWNER[Vérifier conversation + utilisateur]
    OWNER --> FILE[Servir le fichier]

```

## Secrets et configuration

Le projet contient encore des secrets historiques dans la configuration. Ils ne doivent **jamais** être copiés dans le wiki, le frontend ou les logs. Toute nouvelle intégration devrait préférer les fichiers d’environnement ou une gestion de secrets dédiée plutôt qu’ajouter une nouvelle clé en clair dans le code.

## IA et contrôle d’usage

Le système IA possède des limites de requêtes, budgets, timeouts et plafonds de tokens configurés dans `AI_CONFIG`. Le dossier `src/node.js/server/ai/guard/` contient également la logique de garde liée aux coûts.

## Checklist pour une nouvelle route

- Choisir le guard backend correspondant au niveau d’accès.
- Ne jamais se fier uniquement à l’UI ou au routing Angular.
- Valider les IDs liés à l’utilisateur côté serveur.
- Limiter et valider les entrées volumineuses ou fichiers.
- Ne pas exposer de secret dans une réponse API ou dans Angular.
- Préférer une erreur contrôlée à une exception brute contenant des détails internes.
- Vérifier les permissions avant de lire un fichier ou une ressource appartenant à un autre utilisateur.

# Frontend Angular

Structure du frontend Angular, modules, composants, services, navigation, état et conventions utilisées dans l'application Web.

# Structure et routing Angular

## Structure principale

Le frontend Angular se trouve dans `uniksimFrontEnd/`. Le dossier principal est `src/app/`.

- `Pages/` : écrans complets de l’application.
- `Components/` : composants réutilisables.
- `Popup/` : interfaces modales/popups.
- `service/` : services Angular, auth, pipes et logique partagée.
- `Models/` : modèles TypeScript.
- `constants/` : constantes frontend.
- `styles/` : styles partagés.

## Module racine

`src/app/app.module.ts` centralise actuellement :

- déclarations de pages et composants ;
- Angular Material et autres dépendances UI ;
- configuration des traductions ;
- configuration des notifications ;
- routing principal ;
- guards ;
- intercepteur HTTP d’authentification.

## Familles de routes

- **Publiques** : login, reset de mot de passe, page unauthorized, Chen login.
- **Utilisateur** : logout, game, demo, alpha, etc.
- **Utilisateur Uniksim** : index.
- **Admin** : liste, support, présence.
- **True Admin** : settings, recherche de démos, simulations actives, commentaires, fiche utilisateur.

## Point à connaître

Le routing n’est pas dans un `app-routing.module.ts` séparé : il est défini directement avec `RouterModule.forRoot(...)` dans `app.module.ts`.

# Services Angular et communication avec l’API

## Vue d’ensemble

Le frontend ne doit pas appeler le backend directement depuis chaque composant. La logique partagée est regroupée dans `uniksimFrontEnd/src/app/service/`, avec plusieurs familles spécialisées.

## Flux standard

```mermaid
sequenceDiagram
    participant P as Page / Component
    participant S as Service Angular
    participant I as AuthInterceptor
    participant C as Controller NestJS
    participant B as Service backend

    P->>S: Action utilisateur
    S->>I: Requête HttpClient
    I->>I: Ajoute / gère auth
    I->>C: HTTP
    C->>B: Logique métier
    B-->>C: Résultat
    C-->>S: Réponse
    S-->>P: État / données UI

```

## Auth

`service/auth/` contient :

- `AuthGuard.service.ts` : guards de navigation selon le type d’utilisateur.
- `authInterceptor.service.ts` : intercepteur HTTP enregistré globalement dans `app.module.ts`.

## Accès aux données et APIs

`service/requestAndData/` contient les services historiques de communication et de données :

- `braincloudRequest.service.ts`
- `dataBaseRequest.service.ts`
- `dataSource.service.ts`

Avant de créer un nouveau service HTTP générique, vérifier si l’appel appartient déjà à l’un de ces services ou à un service fonctionnel plus spécifique.

## Support

`service/support/` sépare le support en trois responsabilités :

- `support.service.ts` : appels et logique du support.
- `support-socket.service.ts` : namespace `/support`, rooms de conversations et événements temps réel.
- `support-state.service.ts` : état frontend partagé du support.

## Notifications

`service/notifications/` contient notamment :

- `user-notification.service.ts` : inbox locale, synchronisation HTTP et fusion par UID des notifications transmises par AppComponent.
- `notification-sound.service.ts` : gestion du son lors de nouvelles notifications.

## Présence et WebPanel

- `service/presence/admin-presence.service.ts` : données de présence utilisées par l’interface admin.
- `service/webPanel/web-panel.service.ts` : logique du WebPanel.

## Choisir où placer une nouvelle logique

```mermaid
flowchart TD
    NEW[Nouvelle logique frontend] --> SHARED{Utilisée par plusieurs pages ?}
    SHARED -- Non --> PAGE[La garder près de la Page / Component]
    SHARED -- Oui --> DOMAIN{Sous-système existant ?}
    DOMAIN -- Auth --> AUTH[service/auth]
    DOMAIN -- Support --> SUP[service/support]
    DOMAIN -- Notifications --> NOTIF[service/notifications]
    DOMAIN -- Présence --> PRES[service/presence]
    DOMAIN -- Données / API générique --> DATA[service/requestAndData]
    DOMAIN -- Autre --> NEWSVC[Nouveau service spécialisé]

```

## Points d’attention

- Éviter de dupliquer les appels HTTP dans plusieurs pages.
- Garder les composants centrés sur l’UI et déléguer la logique partagée aux services.
- Pour le temps réel, toujours prévoir le chargement initial HTTP et la mise à jour Socket.IO.
- Lorsqu’un endpoint change, vérifier le service Angular correspondant et non seulement la page visible.

## Temps réel du compte et transport partagé — septembre 2026

`service/realtime/realtime-socket.ts` centralise connexion JWT, événements observables, reconnexion et acknowledgements. `service/account/account-socket.service.ts` utilise `/account` pour présence, télémétrie consentie, jeu actif et `notification.created`. `service/support/support-socket.service.ts` utilise `/support` pour messages, tickets et typing, et restaure la conversation active à la reconnexion. Les composants de support et de présence admin consomment le service du compte pour les signaux de présence.

`AccountSocketService` joue le son et émet la notification; `AppComponent` la transmet à `UserNotificationService.upsert()`. Les modèles sont séparés dans `Models/Notification.ts`, `Presence.ts` et `Support.ts`; les constantes communes vivent dans `realtime.constants.ts` et `account.constants.ts`. Voir [Support temps réel](https://wiki.uniksim.com/books/web/page/support-temps-reel).

# Pages, composants et structure UI

## Vue d’ensemble

Le frontend sépare globalement les **écrans complets**, les **composants réutilisables** et les **popups**. Cette page sert de guide pour savoir où ajouter ou modifier une interface.

## Structure UI

```mermaid
flowchart TD
    APP[AppModule] --> ROUTES[RouterModule.forRoot]
    ROUTES --> PAGES[Pages]
    PAGES --> COMP[Components]
    PAGES --> POP[Popup]
    PAGES --> SERVICES[Services Angular]
    COMP --> SERVICES

```

## Pages

`src/app/Pages/` contient les écrans routables ou les grosses vues fonctionnelles. Les dossiers actuellement présents incluent notamment :

- `PageLogin`, `PageForgotPassword`, `PageUnauthorized`
- `PageIndex`
- `PageWebgl`
- `PageSupport` et `PageSupportAdmin`
- `PageAdminPresence`
- `PageTableList` et `PageUserInformation`
- `PageSettings`, `PageDemoSearch`, `PageActiveSimulation`, `PageSimulationComments`

## Components

`src/app/Components/` contient les composants destinés à être utilisés par d’autres vues. On y trouve notamment `CommunicationOverlay` et `WebPanel`.

Un élément devrait devenir un composant partagé lorsqu’il possède une responsabilité UI autonome ou qu’il est utilisé par plusieurs pages.

## Popup

`src/app/Popup/` regroupe les interfaces modales. Lorsqu’une interaction est temporaire et ne mérite pas une route complète, vérifier d’abord si elle appartient à cette couche.

## Routing

Le routing est centralisé directement dans `src/app/app.module.ts` avec `RouterModule.forRoot(...)`. Il n’existe pas de `app-routing.module.ts` séparé.

Les routes sont regroupées par niveau d’accès : publiques, utilisateur, utilisateur Uniksim, admin et true admin. Voir **Structure et routing Angular** pour la liste détaillée.

## Créer une nouvelle vue

```mermaid
flowchart LR
    NEED[Nouvelle interface] --> ROUTE{Doit avoir une URL ?}
    ROUTE -- Oui --> PAGE[Nouvelle Page]
    PAGE --> APP[Ajouter déclaration + route dans app.module.ts]
    ROUTE -- Non --> REUSE{Réutilisable ?}
    REUSE -- Oui --> COMPONENT[Component]
    REUSE -- Non --> POPUP{Interaction modale ?}
    POPUP -- Oui --> P[Popup]
    POPUP -- Non --> LOCAL[Composant local à la page]

```

## Conventions pratiques

- Une Page orchestre l’écran; elle ne devrait pas absorber toute la logique métier.
- Les appels backend réutilisables passent par les services Angular.
- Un composant partagé ne devrait pas dépendre inutilement d’une route précise.
- Lorsqu’une page devient très volumineuse, extraire les parties UI cohérentes plutôt que créer une deuxième page sans raison.
- Avant de créer un nouveau composant, vérifier si un équivalent existe déjà dans `Components/` ou `Popup/`.

# Panel Web — interface superposée au jeu et intégration Unity

## Le panel au-dessus du jeu

Le panel Web donne accès au support UnikBot et au centre de notifications pendant que le jeu Unity WebGL reste affiché. Angular dessine la barre d'outils et les fenêtres au-dessus du canvas Unity. L'utilisateur ouvre une vue, l'utilise puis la ferme pour retrouver le jeu.

Le composant `app-web-panel` est monté dans `AppComponent`, à côté du `router-outlet`. Il est partagé avec les autres pages du site. Dans le jeu, il reçoit la classe `game-panel-host`, qui adapte sa disposition à la barre d'outils.

## Barre d'outils en jeu

La barre `game-tools-rail` apparaît lorsque l'utilisateur est authentifié, que la route est `/game`, `/demo`, `/alpha`, `/alpha2` ou `/demoLive`, et que `WebPanelService.isGameReady` vaut `true`.

- La cloche ouvre le centre de notifications et affiche son nombre de notifications non lues.
- Le bouton UnikBot ouvre le support et affiche son compteur de messages non lus.
- La poignée replie ou déplie la barre. Quand elle est repliée, un badge conserve le total des deux compteurs, plafonné visuellement à `99+`.
- Replier la barre ferme la vue ouverte. Ouvrir une vue redéplie la barre.

`AppComponent.openGamePanel()` appelle `WebPanelService.toggle()` : cliquer une seconde fois sur la vue active la ferme; choisir l'autre bouton change de vue.

## État partagé et cycle d'ouverture

`WebPanelService` conserve la vue active dans un `BehaviorSubject`. `activePanel$` informe le composant du changement et `currentPanel` expose sa valeur courante. Une seule vue est active à la fois.

<table id="bkmrk-valeur-interne-vue-a"><thead><tr><th>Valeur interne</th><th>Vue affichée</th></tr></thead><tbody><tr><td>`null`</td><td>Panel fermé.</td></tr><tr><td>`notifications`</td><td>Centre de notifications.</td></tr><tr><td>`chat`</td><td>Support Web UnikBot : `app-page-support` en mode compact.</td></tr></tbody></table>

`open(panel)` sélectionne une vue, `toggle(panel)` alterne ouverture et fermeture, et `close()` remet la sélection à `null`. La touche Échap et le bouton de fermeture appellent `close()`.

## Intégration avec Unity WebGL

`PageWebglComponent` héberge `#unity-canvas` et charge le build Unity. À son initialisation, il appelle `setGameReady(false)`. Son listener `window:uniksim:game-ready` passe ensuite l'état à `true` au prochain `requestAnimationFrame`, ce qui rend la barre disponible.

Le composant du panel écoute aussi `window:uniksim:open-panel`. Le champ `detail` accepte une chaîne ou un objet avec `panel`. Seules les valeurs `notifications` et `chat` sont reconnues. Cette entrée permet à un appelant de demander l'ouverture sans changer la route Angular.

```
window.dispatchEvent(new CustomEvent('uniksim:open-panel', {
  detail: { panel: 'notifications' }
}));
```

Dans la branche Game `refactor_notifications`, `MainControlStudent.Start()` et l’initialisation de `MainControlTeacher` appellent `WebGameReadyBridge.Notify()`. En build WebGL, ce bridge appelle `NotifyWebGameReady()` dans `Assets/Src/Plugins/javaLib.jslib`, qui émet `uniksim:game-ready`. Angular reçoit cet événement et affiche les outils. Dans l’éditeur Unity, le bridge écrit seulement un log.

À la destruction de `PageWebglComponent`, `setGameReady(false)` masque les outils du jeu. Le composant enregistre aussi le jeu actif avec `AccountSocketService.setGamePresence(pid, gameUid)` après validation de l'accès, puis appelle `clearGamePresence()` à la sortie.

## Support UnikBot

La vue support embarque `PageSupportComponent` avec `compact=true`. Ce mode conserve la présentation du jeu : le composant ne réactive pas l'en-tête et le pied de page du site.

Le support charge la conversation IA et les tickets de l'utilisateur. Il gère le fil sélectionné, les nouveaux messages, les mises à jour de tickets, les indicateurs de saisie et le statut des administrateurs. `SupportService` porte les appels métier, `SupportStateService` réconcilie les données et `SupportSocketService` fournit les événements temps réel.

La fenêtre support utilise un fond assombri cliquable pour fermer le panel. Sur ordinateur, elle peut atteindre 880 × 700 px, dans les limites du viewport. En mode jeu, elle est décalée pour laisser la barre accessible. Sur petit écran, elle occupe presque toute la surface et réserve de l'espace aux outils.

Voir [Support temps réel](https://wiki.uniksim.com/books/web/page/support-temps-reel) pour les conversations et les transports.

## Centre de notifications

La vue notifications est un popover positionné près de la cloche. Sa position est recalculée à l'ouverture, au redimensionnement et au scroll. Sur ordinateur dans le jeu, il apparaît à gauche de la barre. Sa largeur est limitée à 380 px; sa liste défile lorsque le contenu dépasse la hauteur disponible.

La couche externe laisse passer les interactions vers le jeu avec `pointer-events: none`; la fenêtre réactive ses propres interactions. Un clic hors de la fenêtre et de la cloche ferme la vue.

`UserNotificationService` partage la liste entre le panel et les compteurs :

<table id="bkmrk-action-api-web-charg"><thead><tr><th>Action</th><th>API Web</th></tr></thead><tbody><tr><td>Charger la liste</td><td>`GET /notifications`</td></tr><tr><td>Marquer comme lu</td><td>`POST /notifications/:uid/read` avec `isRead`</td></tr><tr><td>Supprimer</td><td>`DELETE /notifications/:uid`</td></tr></tbody></table>

La première ouverture charge la liste; le bouton de rafraîchissement permet de la recharger. Le panel affiche les états de chargement, d'erreur avec nouvelle tentative, et de liste vide. Cliquer une notification non lue la marque comme lue; le bouton de suppression retire l'entrée sans déclencher ce clic de lecture.

`AccountSocketService.onNotificationCreated$` alimente `UserNotificationService.upsert()`, qui fusionne les entrées par UID. `AppComponent` recharge les notifications après reconnexion du compte. Les titres et corps utilisent `uniksim.notification_<type>_title` et `_body`, avec un texte par défaut si la traduction manque.

Côté Game, `NotificationManager.SaveNotification()` délègue à `BackEndBase.SaveNotification()`, qui envoie `POST /saveNotification`. L'affichage du panel et sa liste sont gérés côté Web. Voir [Notifications et Push](https://wiki.uniksim.com/books/web/page/notifications-et-push) pour la réception serveur, l'inbox et le push.

## Fichiers à modifier

<table id="bkmrk-fichier-responsabili"><thead><tr><th>Fichier</th><th>Responsabilité</th></tr></thead><tbody><tr><td>`uniksimFrontEnd/src/app/app.component.html`, `.ts` et `.scss`</td><td>Montage global, barre en jeu, boutons, compteurs et accès hors jeu.</td></tr><tr><td>`service/webPanel/web-panel.service.ts`</td><td>Vue active et état de disponibilité du jeu.</td></tr><tr><td>`Components/WebPanel/WebPanel.component.ts`, `.html` et `.scss`</td><td>Ouverture, fermeture, contenu, position et superposition.</td></tr><tr><td>`Pages/PageWebgl/PageWebgl.component.ts`</td><td>Chargement Unity, disponibilité et cycle du jeu actif.</td></tr><tr><td>`Pages/PageSupport/` et `service/support/`</td><td>Support embarqué et ses conversations.</td></tr><tr><td>`service/notifications/user-notification.service.ts`</td><td>Liste, compteur et mutations de notifications.</td></tr><tr><td>`service/account/account-socket.service.ts`</td><td>Événements du compte et jeu actif.</td></tr><tr><td>`Game/Assets/Src/Game/Notifications/NotificationManager.cs` et `Game/Assets/Src/Game/BackEnd/BackEndBase.cs`</td><td>Envoi des notifications depuis Unity.</td></tr></tbody></table>

## Vérifier une modification

- Entrer dans le jeu : les outils attendent le signal de disponibilité.
- Ouvrir chaque vue depuis la barre, changer de vue, recliquer le bouton actif, fermer avec Échap et avec la croix.
- Replier la barre avec une vue ouverte, puis la redéplier; contrôler les compteurs.
- Contrôler le placement sur ordinateur et petit écran, et les clics qui doivent atteindre le jeu autour du popover.
- Tester le support intégré, le chargement des notifications, la lecture, la suppression et une reconnexion.
- Sortir du jeu : vérifier le retrait des outils et du jeu actif côté compte.

Sources de cette page : frontend Web de la branche `messagerie_fixes` et code Game de la branche `refactor_notifications`, inspecté le 30 septembre 2026.

# Intégrations et systèmes transversaux

Intégrations qui traversent plusieurs couches : Unity WebGL, support temps réel, IA/RAG, notifications, fichiers et services externes.

# Unity WebGL et communication avec le Web

## Vue d’ensemble

Le jeu Unity WebGL est intégré au site Angular et communique avec le backend NestJS. Cette page présente les responsabilités de chaque couche et les principaux points à vérifier lorsqu’une modification touche le jeu et le Web.

## Architecture générale

```mermaid
flowchart LR
    USER[Utilisateur] --> ANG[Angular / PageWebgl]
    ANG --> BUILD[Build Unity WebGL]
    BUILD --> UNITY[Runtime Unity]

    UNITY -->|HTTP| GAME[GameController]
    GAME --> GS[GameService]

    GS --> BC[BrainCloud]
    GS --> REDIS[(Redis)]
    GS --> STORAGE[storage / images / logs]

    ANG -->|Auth / session / navigation| NEST[NestJS]
    NEST --> ANG

```

## Côté Angular

`PageWebglComponent` est l’écran qui héberge le jeu pour plusieurs routes, notamment `/game`, `/demo`, `/alpha`, `/alpha2` et `/demoLive`.

Le build Unity est livré dans les assets frontend. Le frontend Angular gère le contexte Web autour du jeu : navigation, authentification, chargement et communication avec les autres fonctions du site.

## Côté backend

`GameController` dans `uniksim-back-end/src/app.controller.ts` est protégé par `AuthGuardGame`. Il délègue la logique à `GameService`.

Les endpoints couvrent notamment :

- version du build;
- informations de code produit;
- textes et traductions;
- écoles;
- token Web;
- heartbeat et présence en jeu;
- classements;
- images utilisateur;
- journalisation de crash.

## Flux heartbeat

```mermaid
sequenceDiagram
    participant U as Unity WebGL
    participant G as GameController
    participant S as GameService / server.js
    participant R as Redis

    U->>G: heartBeat(simUid, userUid, token)
    G->>S: heartBeat(...)
    S->>R: Vérifie session / présence
    R-->>S: État session
    S->>R: Met à jour présence + expiration
    S-->>G: Version / heartbeats / sessionTime
    G-->>U: Réponse

```

## Build et fichiers statiques

Les assets Unity font partie du frontend Angular. Le build Angular de production est ensuite généré dans `uniksim-back-end/src/front`, puis servi par NestJS avec `ServeStaticModule`.

Voir **Build et déploiement Web** pour l’ordre complet de build.

## Quand modifier plusieurs projets

Une modification du contrat Unity/Web nécessite souvent de vérifier plusieurs couches :

```mermaid
flowchart LR
    CHANGE[Changement Unity / Web] --> UNITY[Code Unity]
    CHANGE --> ANG[Angular / PageWebgl]
    CHANGE --> API[GameController]
    API --> SERVICE[GameService]
    SERVICE --> DATA[BrainCloud / Redis / stockage]

    UNITY --> TEST[Test WebGL]
    ANG --> TEST
    API --> TEST

```

## Fichiers à connaître

- `uniksimFrontEnd/src/app/Pages/PageWebgl/`
- `uniksimFrontEnd/src/assets/unity/`
- `uniksim-back-end/src/app.controller.ts` — `GameController`
- `uniksim-back-end/src/service/game.service.ts`
- `uniksim-back-end/src/guards/authGame.guard.ts`
- `uniksim-back-end/src/node.js/server/server.js`
- `uniksim-back-end/src/node.js/server/backend_braincloud.js`

## Points d’attention

- Ne pas modifier seulement le frontend si le format attendu par Unity ou l’API change.
- Vérifier le guard et le contexte d’instance (live/dev/demo) pour les endpoints du jeu.
- Les heartbeats ont des effets sur Redis et la présence; les traiter comme un flux runtime important.
- Après un nouveau build Unity, vérifier que les nouveaux fichiers WebGL sont bien ceux inclus dans les assets/build déployés.

## Présence du compte et notifications après refactoring

`PageWebglComponent` transmet le jeu actif à `AccountSocketService.setGamePresence(productCodeId, gameUid)` et l’efface à la sortie. Cette présence sur `/account` complète le heartbeat/session HTTP du jeu : les deux chemins ont des responsabilités distinctes. La reconnexion du compte restaure le jeu actif.

Le jeu envoie les notifications via `POST /saveNotification`; `userUid` désigne le profil jeu destinataire et `extraData.simUid` la simulation. Ce contrat est traité par `NotificationController` avec `AuthGuardUser`, puis `GameNotificationService`, et non par `GameController`. Le serveur vérifie expéditeur et destinataire dans le document BrainCloud puis utilise l’inbox et le push du compte Web. Voir [Notifications et Push](https://wiki.uniksim.com/books/web/page/notifications-et-push).

# Notifications et Push

## Vue d’ensemble

Toutes les notifications passent par `NotificationService.notify(userId, notificationType, payload, isImportant)`. Le compte reçoit une entrée dans son inbox Redis, un événement Socket.IO sur `/account` et une tentative de push FCM vers ses installations. Le Web et l’application mobile lisent l’inbox; le jeu produit des notifications via l’API.

## Flux de création et responsabilités

```mermaid
flowchart LR
S[Service métier ou GameNotificationService] --> N[NotificationService.notify]
N --> R[(Inbox Redis du compte)]
N --> E[EventEmitter notification.created]
E --> G[AccountGateway /account]
G --> A[AccountSocketService]
A --> U[UserNotificationService et interface]
N --> F[FirebaseService]
F --> T[(UserFcmToken)]
F --> D[FCM vers installations du compte]
```

1. Vérifier que le compte destinataire existe.
2. Construire l’enveloppe avec UID unique, puis sauvegarder l’inbox.
3. Émettre `notification.created`; `AccountGateway` relaie la notification vers `user_<userId>` dans le namespace `/account`.
4. Construire le titre et le corps localisés, puis tenter le push. Une erreur de push est journalisée sans annuler l’entrée déjà sauvegardée.

## Contrat partagé

`NotificationDto` côté backend et `UserNotification` côté Angular partagent les champs `uid, userId, notificationType, timestamp, isRead, isImportant`. Les champs métier, par exemple `ticketId` ou `simUid`, sont placés directement à côté de cette enveloppe. Les champs d’enveloppe définis par le serveur écrasent ceux du payload.

L’UID combine le compte, le timestamp et quatre octets aléatoires pour distinguer plusieurs notifications créées dans la même milliseconde. Le texte push utilise les clés `uniksim.push_<type>_title/body`, les placeholders du payload et un texte de secours. Les valeurs FCM sont converties en chaînes; `notificationUid` conserve la compatibilité avec les clients historiques.

## Inbox Redis et API du compte

La clé est `user_<id>_notifications`. `LPUSH` conserve les plus récentes en premier, `LTRIM` limite l’inbox à 100 entrées et `EXPIRE` fixe 10 519 200 secondes de rétention. Chaque insertion renouvelle le TTL de toute la liste; ce n’est pas une expiration indépendante par notification.

<table id="bkmrk-action-endpoint-comp"><thead><tr><th>Action</th><th>Endpoint</th><th>Comportement</th></tr></thead><tbody><tr><td>Charger</td><td>`GET /notifications`</td><td>Retourne l’inbox du compte authentifié.</td></tr><tr><td>Lu / non lu</td><td>`POST /notifications/:notificationUid/read`</td><td>Met à jour l’entrée par UID avec `LSET`.</td></tr><tr><td>Supprimer</td><td>`DELETE /notifications/:notificationUid`</td><td>Retire l’entrée avec `LREM`.</td></tr></tbody></table>

Ces routes utilisent `AuthGuardUser` et l’identité `request.user.sub`.

## Frontend et temps réel

`AccountSocketService` reçoit `notification.created`, déclenche le son et expose l’observable. `AppComponent` transmet la notification à `UserNotificationService.upsert()`. Ce service maintient le `BehaviorSubject`, déduplique par UID et dérive le nombre de notifications non lues. Le chargement initial et les actions lu/suppression utilisent HTTP. `SupportSocketService` gère les conversations et tickets; la réception des notifications appartient au service du compte.

## Installations et livraison FCM

`PUT /push/installations/:installationId` enregistre `token` et `platform` pour le compte authentifié. Dans une transaction, le service supprime les inscriptions périmées portant le même token puis crée ou met à jour `UserFcmToken`. `DELETE /push/installations/:installationId` retire l’installation de ce compte.

La livraison charge toutes les installations du compte, déduplique les tokens et les envoie par lots via `sendEachForMulticast`. Les tokens invalides ou désenregistrés entraînent la suppression de leurs installations. Le modèle actuel ne contient plus `UserFcmSubscription` ni de filtrage des appareils par productCode. Si les variables Firebase sont absentes, le push est désactivé mais l’inbox reste utilisable.

## Notifications envoyées par le jeu

`POST /saveNotification` reçoit `userUid` (profil jeu du destinataire), `notificationType`, `extraData` et éventuellement `isImportant`. `GameNotificationService` traduit le profil actif `ProductsCode.gameOid` en compte Web et vérifie la simulation BrainCloud indiquée par `extraData.simUid`.

L’expéditeur doit posséder un profil actif membre de cette simulation; le destinataire doit aussi en être membre. Le serveur utilise `teacherUid` et les clés de `students` du document pour cette vérification. Les types réservés au support sont refusés, le payload JSON est limité à 2 048 caractères et les identifiants à 255 caractères. La vérification BrainCloud expire après dix secondes. Une fois validée, la notification suit exactement le flux commun `notify()`.

## Fichiers principaux

- `src/service/notification.service.ts`, `game-notification.service.ts`, `firebase.service.ts`
- `src/dto/notification.dto.ts`, `src/gateway/account.gateway.ts`, `src/guards/socketAuth.middleware.ts`
- `src/app.controller.ts` et `NOTIFICATION_CONFIG` dans `src/node.js/server/constantsVariable.js`
- Angular : `service/account/account-socket.service.ts`, `service/realtime/realtime-socket.ts`, `service/notifications/user-notification.service.ts`, `Models/Notification.ts`
- Tests : `test/notification/notification.service.test.ts` et `game-notification.service.test.ts`

Voir aussi [Support temps réel](https://wiki.uniksim.com/books/web/page/support-temps-reel).

# Services externes et dépendances

## Vue d’ensemble

Plusieurs fonctions du Web dépendent de services externes ou de couches historiques. Cette page sert de carte pour comprendre **quelle dépendance intervient où** et quels fichiers vérifier lorsqu’une intégration tombe en panne.

## Carte des intégrations

```mermaid
flowchart LR
    NEST[NestJS principal] --> MYSQL[(MySQL)]
    NEST --> REDIS[(Redis)]
    NEST --> BC[BrainCloud]
    NEST --> FCM[Firebase / FCM]
    NEST --> MAIL[Mail]
    NEST --> AI[Serveur IA :8106]

    ADMIN[Admin Server :8105] --> BC
    ADMIN --> REDIS

    AI --> CHROMA[(Chroma)]
    AI --> PROVIDER[Provider IA]

    UNITY[Unity WebGL] --> NEST
    ANG[Angular] --> NEST
    ANG <-->|Socket.IO| NEST

```

## BrainCloud

BrainCloud est encore utilisé par plusieurs fonctions historiques liées aux simulations et au jeu.

Fichiers importants :

- `src/node.js/server/backend_braincloud.js`
- `src/node.js/server/server.js`
- `src/node.js/server/admin_server.js`
- `src/service/game.service.ts`

Lorsqu’un bug concerne une simulation, une copie de simulation, certains documents de jeu ou des opérations historiques admin, vérifier si le flux passe par BrainCloud avant de modifier MySQL.

## Redis

Redis est utilisé pour les données runtime : présence, sessions, rankings, notifications et autres informations temporaires.

Fichier principal : `src/service/redis.service.ts`. Certaines couches historiques l’utilisent également depuis `src/node.js/server/`.

## Firebase / FCM

Firebase Cloud Messaging assure les push notifications vers les appareils enregistrés.

Fichiers principaux :

- `src/service/firebase.service.ts`
- `src/service/notification.service.ts`
- `UserFcmToken` dans les entités TypeORM.

Voir **Notifications et Push** pour le flux complet.

## IA / Chroma

Le serveur IA est séparé logiquement sous `src/node.js/server/ai/` et utilise un provider de génération, un provider d’embeddings et Chroma pour la recherche vectorielle.

Fichiers importants :

- `src/service/ai.service.ts`
- `src/node.js/server/ai/server.js`
- `src/node.js/server/ai/provider/`
- `src/node.js/server/ai/factory/`
- `src/node.js/server/ai/guard/`
- `src/embedding/`

Voir le chapitre **Support et IA** pour le pipeline RAG et l’ajout de providers.

## Mail

Le backend possède une couche mail utilisée notamment pour le reset de mot de passe et les courriels applicatifs.

- `src/service/mail.service.ts`
- `src/mail/`
- `MailController` dans `app.controller.ts`

## Comment diagnostiquer une intégration

```mermaid
flowchart TD
    BUG[Erreur d’intégration] --> LOCAL{Le backend reçoit la requête ?}
    LOCAL -- Non --> FE[Frontend / réseau / auth]
    LOCAL -- Oui --> SERVICE[Identifier le service backend]
    SERVICE --> EXT{Appel externe ?}
    EXT -- Non --> INTERNAL[Logique interne / DB]
    EXT -- Oui --> WHICH{Quelle dépendance ?}
    WHICH --> BC[BrainCloud]
    WHICH --> R[Redis]
    WHICH --> F[Firebase]
    WHICH --> AI[IA / Chroma]
    WHICH --> M[Mail]
    BC --> LOG[Logs + config + credentials]
    R --> LOG
    F --> LOG
    AI --> LOG
    M --> LOG

```

## Points d’attention

- Ne jamais documenter de clé API, mot de passe ou credential en clair.
- Vérifier la configuration d’environnement avant de conclure que le service externe est en panne.
- Plusieurs intégrations possèdent une couche historique et une couche NestJS moderne; identifier le chemin réellement utilisé avant de modifier le code.
- Lorsqu’une dépendance externe échoue, distinguer l’échec réseau/provider d’un problème de mapping ou de logique interne.

## Contrats d’intégration actuels — septembre 2026

Gemini utilise `@google/genai` en mode Vertex AI via `provider/gemini/vertex_client.js`. La configuration utilise `GOOGLE_CLOUD_PROJECT`, `GOOGLE_CLOUD_LOCATION=global` et les credentials Google par défaut de l’environnement. Chroma utilise `CloudClient` avec `CHROMA_API_KEY`, `CHROMA_TENANT` et `CHROMA_DATABASE`; la collection configurée est `game`.

Firebase envoie les notifications à toutes les installations du compte stockées dans `UserFcmToken`. La validation des membres d’une simulation pour les notifications du jeu relève de `GameNotificationService` et de BrainCloud; les installations ne sont plus sélectionnées par subscription produit.

Socket.IO sépare `/account` (présence et notifications) et `/support` (conversations et tickets). L’initialisation IA en arrière-plan permet au serveur principal de démarrer même si un provider ou Chroma est temporairement indisponible.

# Site Uniksim (Old)

Information sur tout ce qui concerne le site web de uniksim. Principalement pour l'équipe de développement.

# Note uniksimWeb

##### <span style="text-decoration: underline;">Les versions utilisées sur le site :</span>

- Node.js v.22.5.1
- Angular v.18.2.11 (FrontEnd)
- NestJs v.11.0.11 (BackEnd)

Angular / NodeJs compatibilité : [Lien](https://stackoverflow.com/questions/60248452/is-there-a-compatibility-list-for-angular-angular-cli-and-node-js)

<table border="1" id="bkmrk-changer-de-version-a" style="border-collapse: collapse; width: 100%;"><tbody><tr><td style="width: 100%;">Changer de version avec nvm (Node Version Manager) : `nvm use *<em>version</em>`

Voir la liste sur nvm (Node Version Manager) : `nvm list`

Voir les packages outdated : `npm outdated`

Mettre à jour les packages (classique) : `npm update` \*cela update redis!

Mettre à jour les packages (avec npm-check-updates) : `npx npm-check-updates -u` \*cela update redis!

</td></tr></tbody></table>

<table border="1" id="bkmrk-node-version-%3A-node-" style="border-collapse: collapse; width: 100%;"><tbody><tr><td style="width: 100%;">Node version : `node -v`

Angular version : `ng version`

NestJs version : `nest --version`

\*npm-check-updates (backendEnd) : `npx npm-check-updates`

<p class="callout info">Note : Le fichier package.json possède toutes les versions</p>

<p class="callout info">Note : Ne pas oublier de faire un `npm install` dans backendEnd et frontEnd</p>

</td></tr></tbody></table>

##### <span style="text-decoration: underline;">Les imports importants NestJs :</span>

<div id="bkmrk-typeormmodule-%3A-comm"><div><div>- TypeOrmModule : Communication et conversion des données avec la mySql (Query)
- <div><div>DatabaseProviders : Connection avec mySql</div></div>
- Guard : Authentification et accès
- MailGun : Système de messagerie
- Generate Password TS : Système de génération de mot de passe (mot de passe oublié)

</div></div></div>Pour plus de détails voir : **app.module.ts** ou **package.json**

##### <span style="text-decoration: underline;">Les roles :</span>

<div id="bkmrk-user%3A-permission-de-"><div><div>- user: 
    - Permission de jouer (Games uniquement)
- user\_uniksim: 
    - Permission d'accès au site
    - Permission de jouer
- admin\_user: 
    - Permission d'accès au site
    - Permission de jouer
    - Permission avec accès limité à la page admin
- admin: 
    - Toute permission

</div></div></div>\*note: Il existe un role superAdmin, mais cela n'est pas vraiment utilisé...

##### <span style="text-decoration: underline;">DigitalOcean (Update branch) :</span>

Si vous avez accès à DigitalOcean, vous pouvez faire des changements sur le site en version live\* (Principalement pour des updates en Git)

*\*Ici "live" peut-être un site de développement avec un domain, pas forcément le vrai site*

*\*\*n'oublie pas de builder vos channgements avant d'update! (frontend surtout)*

<div id="bkmrk-dans-la-section%2C-dro">1. Dans la section, ****Droplets****, puis le dossier du site en question ![](https://wiki.uniksim.com/uploads/images/gallery/2024-08-Aug/scaled-840-0/image-1723218630153.png)
2. Ensuite dans ****Console****![](https://wiki.uniksim.com/uploads/images/gallery/2024-08-Aug/scaled-840-0/image-1723218747353.png)
    
    
    - Vous devriez voir une console en linux pour faire les modifications
3. Naviguer à travers les fichiers pour trouver le dossier recherché ![](https://wiki.uniksim.com/uploads/images/gallery/2024-08-Aug/scaled-840-0/image-1723218954045.png)
    
    
    - Note 1: Les commandes git se font généralement sur le fichier source (Dans ce cas **sim.uniksim.com**)
    - Note 2: Durant un `npm install` sur la console de Droplet, il faudrait ajouter `--legacy-peer-deps` à la fin. (la version de Droplet est plus récente) 
        - Note 2.1: Un `npm audit fix` pourrait être intéressant pour fix les soucis de package conflict. \[Autre Solution Non recommandé\] Pour être aussi `npm audit fix --force`, cependant ceci risque de brisser des packages.
    - Note 3: Il se peut que le dossier source **root** n'est pas le dossier recherché, puisque votre **username** de base de donnée (database) n'est pas le même. ![](https://wiki.uniksim.com/uploads/images/gallery/2024-08-Aug/scaled-840-0/image-1723220094918.png)
        
        
        - Faire la commande suivante si c'est le cas (**forge** fait référence au **username**, changer selon le cas) 
            - <p class="callout info">su - forge</p>
4. Utiliser les commandes nécessaire à vos changements 
    - Remettre à l'état d'origine le dossier 
        - <p class="callout info align-left">git reset .</p>
        - <p class="callout info">git reset --hard</p>
            
            
            - `git reset --hard` risque de nécessiter `origin/master` comme paramètre
    - Récupérer la branch commit  
        
        - <p class="callout info align-left">git pull</p>
    - Aller vers la branche 
        - <p class="callout info align-left">git checkout</p>
    - Voir l'état de la branche actuel 
        - <p class="callout info align-left">git status</p>
    - Similaire à reset, elle permet de retirer les dossiers non nécessaires 
        - <p class="callout info align-left">git clean -fd</p>
5. Faire `cd uniksim-back-end`, puis faire `npm run build` pour appliquer les changements
6. (optionnel) Faire `npm run start` pour lancer le site. \*n'oublie de faire de même pour admin\_server si nécessaire

</div>##### <span style="text-decoration: underline;">Cookieyes :</span>

Url : [https://app.cookieyes.com/](https://app.cookieyes.com/)

Script url : [https://cdn-cookieyes.com/client\_data/b08568c123e8efb0b38c9ce6/script.js](https://cdn-cookieyes.com/client_data/b08568c123e8efb0b38c9ce6/script.js)

##### <span style="text-decoration: underline;">Build :</span>

- Pour les build, utiliser la commande **Build Frontend project**![](https://wiki.uniksim.com/uploads/images/gallery/2024-08-Aug/scaled-840-0/image-1723139133125.png)
    
    
    - Si cela n'est pas possible, utiliser la commande ci-dessous dans un terminal (dans le dossier uniksimFrontEnd)

<p class="callout info">ng build</p>

- Vous devriez avoir créer un build nommer **Front** dans le dossier ****uniksim-back-end****![](https://wiki.uniksim.com/uploads/images/gallery/2024-08-Aug/scaled-840-0/image-1723139458662.png)
- Par la suite **ServeStaticModule** (Permet de rendre le build static et disponible pour le serveur) va pourvoir recréer ce dossier à l'intérieur de **dist**, lorsque le serveur sera en marche.
- Note: le fichier **nest-cli.json** est important pour importer tous les fichiers du dossier **front** généré. Spécifiquement la ligne : `{ "include": "front/**/*"}`  
    ![](https://wiki.uniksim.com/uploads/images/gallery/2024-08-Aug/scaled-840-0/image-1723139953468.png)
- Note: si vous changez unity build (ex: Build.data.unityweb), s'assurer de mettre la même version dans ****constantsVariable****![](https://wiki.uniksim.com/uploads/images/gallery/2025-01-Jan/scaled-840-0/image-1737392002764.png)

##### <span style="text-decoration: underline;">Notes :</span>

- Dans **database.providers.ts**, "synchronize" permet de faire en sorte que les entitées de node.js (typeOrm) sont créer ou modifier sur Sql. Il est donc préférable de le laisser **false**
- Si vous voulez augmenter la taille maximum pour le phpmyadmin suivre ce post: <p class="callout info">[https://stackoverflow.com/questions/3958615/import-file-size-limit-in-phpmyadmin](https://stackoverflow.com/questions/3958615/import-file-size-limit-in-phpmyadmin "https://stackoverflow.com/questions/3958615/import-file-size-limit-in-phpmyadmin")</p>
- La commande pour envoyer le serveur backend en local (il faut bien sûr "cd" dans le bon dossier) :  
    <p class="callout info">npm run start</p>
    
    
    - Version en live/demo :  
        <p class="callout info">npm run start:live</p>
        
        
        - Cette commande nécessite le build `npm run build`

- - Celui du frontend est :  
        <p class="callout info">ng serve</p>

- Pour debug le code du frontend (Angular), il faudra utiliser l'inspecteur du navigateur (Dans source)
- Accès au SQL : [https://db.uniksim.com/phpmyadmin/sql.php?server=1&amp;db=uniksim&amp;table=constants&amp;pos=0](https://db.uniksim.com/phpmyadmin/sql.php?server=1&db=uniksim&table=constants&pos=0 "https://db.uniksim.com/phpmyadmin/sql.php?server=1&db=uniksim&table=constants&pos=0")
- La commande pour lancer admin\_server (après su- forge) :  
    <p class="callout info">node sim.dev.uniksim.com/uniksim-back-end/src/node.js/server/admin\_server.js</p>
    
    
    - Il est possible d'ajouter un paramètre : `node admin_server.js dev`

##### <span style="text-decoration: underline;">Problèmes :</span>

- Si les modifications appliqués sur le dossier **server** ne sont pas appliqués, vous avez probablement compilé le script sur "dist/../"
- Si vous avez un problème de **ENOENT: no such file or directory, scandir** sur le serveur dev (sim.dev.uniksim), il y a probablement un problème de version dans les packages. Une solution serait de refaire les fichiers non tracés par git (supprimer et installer)
- Si vous avez cette erreur sur la console DigitalOcean ![](https://wiki.uniksim.com/uploads/images/gallery/2025-03-Mar/scaled-840-0/image-1741108107949.png)
    
    
    - Faite `sudo lsof -i :3000` pour trouver le node en cours
    - `~hFHs>!SLx3)d4Yc_HbQ` si nécessaire
    - Puis `kill -9 <PID>` pour le terminer
    - Refaire votre commande

##### <span style="text-decoration: underline;">Les références de création :</span>

- Site de NestJs : [https://docs.nestjs.com/first-steps](https://docs.nestjs.com/first-steps)
- Site de compatibilité de version Angular/Node : [https://v17.angular.io/guide/versions](https://v17.angular.io/guide/versions)
- Léger tread de discussion sur les version NestJs/Node : [https://stackoverflow.com/questions/77160198/how-to-find-supported-node-js-version-for-nest-js](https://stackoverflow.com/questions/77160198/how-to-find-supported-node-js-version-for-nest-js)
- Configuration de NestJs/MySQL (phpMyAdmin) : [https://blog.stackademic.com/connecting-nestjs-to-mysql-a-step-by-step-guide-ab4086baf918](https://blog.stackademic.com/connecting-nestjs-to-mysql-a-step-by-step-guide-ab4086baf918)
    - Other alternative : [https://medium.com/@yatin.kumar07/integrate-nestjs-with-typeorm-and-mysql-68ad4c10f6ff](https://medium.com/@yatin.kumar07/integrate-nestjs-with-typeorm-and-mysql-68ad4c10f6ff)
- Configuration de NestJs : [https://medium.com/@anteprocess/%EF%B8%8Fnestjs-for-beginners-part-1-overview-and-project-setup-launch-33dc7d8071e9](https://medium.com/@anteprocess/%EF%B8%8Fnestjs-for-beginners-part-1-overview-and-project-setup-launch-33dc7d8071e9)
- Imports of node.js (Javascript files) : [https://medium.com/@eladk/moving-from-javascript-to-typescript-lifehacks-e29d7e1aa3e0](https://medium.com/@eladk/moving-from-javascript-to-typescript-lifehacks-e29d7e1aa3e0)
- Decoration pour les expressions Sql : [https://typeorm.io/decorator-reference#column-decorators](https://typeorm.io/decorator-reference#column-decorators)
- Typeorm wiki (NestJs/Sql data communication) : [https://orkhan.gitbook.io/typeorm/docs/find-options](https://orkhan.gitbook.io/typeorm/docs/find-options)
- Debugger for NestJs : [https://dev.to/gentax/nestjs-right-settings-for-debugging-kl0](https://dev.to/gentax/nestjs-right-settings-for-debugging-kl0)
- bCrypt détailes post : [https://stackoverflow.com/questions/15733196/where-2x-prefix-are-used-in-bcrypt/36225192#36225192](https://stackoverflow.com/questions/15733196/where-2x-prefix-are-used-in-bcrypt/36225192#36225192)
- TypeOrm relations (Many-to-one / one-to-many): [https://github.com/typeorm/typeorm/blob/master/docs/many-to-one-one-to-many-relations.md](https://github.com/typeorm/typeorm/blob/master/docs/many-to-one-one-to-many-relations.md)
- Simple Unity/Angular intégration : [https://medium.com/@6386391ritesh/unity-webgl-in-angular-686397677500](https://medium.com/@6386391ritesh/unity-webgl-in-angular-686397677500)
- Build le projet Angular à l'intérieur de Nestjs : [https://medium.com/codeshake/deploy-an-angular-nestjs-app-to-heroku-807a2833d88c](https://medium.com/codeshake/deploy-an-angular-nestjs-app-to-heroku-807a2833d88c)
- SSE notification : [https://medium.com/@andrewkoliaka/implementing-server-sent-events-in-angular-a5e40617cb78](https://medium.com/@andrewkoliaka/implementing-server-sent-events-in-angular-a5e40617cb78)
- Erreur commun pour nvm lorsqu'il refuse de changer de version :[ https://stackoverflow.com/questions/47017812/nvm-use-does-not-switch-node-versions](https://stackoverflow.com/questions/47017812/nvm-use-does-not-switch-node-versions)

# Update/Deploy dans Angular (old)

##### Faire un déployement sur Angular pour Admin (old)

Tous les étapes se font sur Visual Studio Code

<span style="text-decoration: underline;">1) Se déplacer au bon dossier :</span>

- - Avec la command suivante

<p class="callout info">cd {uniksim}/frontend/angular</p>

<span style="text-decoration: underline;">2) Build Angular :</span>

- - Avec la command suivante

<p class="callout info">ng build</p>

<span style="text-decoration: underline;">3) Modifier le **angular.blade.php :**</span>

<p class="callout info">Situé à {uniksim}/resources/views/angular.blade.php</p>

- - Remplacer les balises **html**, **head** et ****base****![](https://wiki.uniksim.com/uploads/images/gallery/2024-05-May/scaled-840-0/image-1716558025848.png)
        
        ![](https://wiki.uniksim.com/uploads/images/gallery/2024-05-May/scaled-840-0/image-1716558113610.png)

<table border="1" id="bkmrk-%40extends%28%27layouts.ap" style="border-collapse: collapse; width: 41.9753%; height: 178px;"><tbody><tr><td style="width: 100%;">@extends('layouts.app')

@section('title')  
{{ trans('uniksim.title\_main') }}  
@stop

@section('applink')

@stop

@section('content')

</td></tr></tbody></table>

- - Remplacer les balises **body** et ****html****![](https://wiki.uniksim.com/uploads/images/gallery/2024-05-May/scaled-840-0/image-1716558305747.png)
        
        ![](https://wiki.uniksim.com/uploads/images/gallery/2024-05-May/scaled-840-0/image-1716558681839.png)

<table border="1" id="bkmrk-%40endsection" style="border-collapse: collapse; width: 42.716%;"><tbody><tr><td style="width: 100%;">@endsection

</td></tr></tbody></table>

- - Retirer la balise ouvrante **body** et la balise fermante **head**

# Debug en Web frontEnd

Avant de commencer assurer vous d'être en *localhost:4200* (à moins qu'il a était changé), car :

- *localhost:4200* utilise le dossier <span style="text-decoration: underline;">frontEnd</span> et <span style="text-decoration: underline;">backEnd</span> (source)
- *localhost:3000* utilise uniquement le <span style="text-decoration: underline;">backEnd</span> (source) et la <span style="text-decoration: underline;">version build du frontEnd</span>

De plus, ce tutoriel va modifier la connexion à titre d'exemple

1. Activer le site sous **Launch Frontend and Backend (dev)**![](https://wiki.uniksim.com/uploads/images/gallery/2025-01-Jan/scaled-840-0/image-1737987681718.png)
2. Vérifier que tout soit en marche : 
    1. Sur le <span style="text-decoration: underline;">frontEnd</span> vous devriez avoir ![](https://wiki.uniksim.com/uploads/images/gallery/2025-01-Jan/scaled-840-0/image-1737987924592.png)
    2. Sur le <u>backend </u>vous devriez avoir (les messages peuvent varier d'ordre) ![](https://wiki.uniksim.com/uploads/images/gallery/2025-01-Jan/scaled-840-0/image-1737987937603.png)
3. Ouvrir une session localhost:4200 web ![](https://wiki.uniksim.com/uploads/images/gallery/2025-01-Jan/scaled-840-0/image-1737988787389.png)
4. Sous Sources­­&gt;Page&gt;webpack://&gt;login&gt;login.component.ts ![](https://wiki.uniksim.com/uploads/images/gallery/2025-01-Jan/scaled-840-0/image-1737988840380.png)
5. Mettre des points d'arrêts sur la requête attendu ![](https://wiki.uniksim.com/uploads/images/gallery/2025-01-Jan/scaled-840-0/image-1737989003122.png)
    
    ![](https://wiki.uniksim.com/uploads/images/gallery/2025-01-Jan/scaled-840-0/image-1737989034392.png)
6. Envoyer la requête, vous devriez commencé à débugger ![](https://wiki.uniksim.com/uploads/images/gallery/2025-01-Jan/scaled-840-0/image-1737989203516.png)

Note: Tous les changements sont sauvegarder automatiquement sur le site local. Si vous avez un doute, faite un changement et sauvegarder. La page devrait se rafraîchir tout seul (s'il n'est pas en debuggeur actuellement). Cependant, le backend est indépendant du frontEnd, donc il faudrait attendre quelque seconde avant d'envoyer la requête (regarder la console pour voir l'état)

# Test de fonctionnalité complète

<span style="color: #000000;">\*note: Les tests ci-dessous sont déjà dans un ordre pour simplifier les tests. Cependant, beaucoup de déconnexions seront requises</span>

#### <span style="text-decoration: underline;">Fonctionnalité - Cas d'utilisateur normal</span>

<table border="1" class="align-left" id="bkmrk-signin-%3A-bouton-pour" style="width: 100%; border-collapse: collapse; border-style: ridge; height: 1623px;"><tbody><tr><td style="width: 50%;">##### Register :

Vérifier que le bouton ***Créer un compte enseignant*** fonctionne, suite aux étapes de création

Vérifier aussi <span style="color: #ff0000;">les cas d'échecs</span>

- Mauvaises informations
- Cases vides
- Mot de passe ou courriel différente
- Décocher l'accord
- Retirer le nom précédamment entré
- Créer un compte existant

<span style="color: #333333;">Ceci devrait créer *un token* (dans LocalStorage)</span>

<span style="color: #000000;">\*note: Si ceci est fait sur le site *Live* ou *Dev*, veuillez l'ajouter sur </span>*<span style="color: #000000;">Compte test - Création de compte </span>*<span style="color: #000000;">(Se trouvant sur le *Wiki*) </span><span style="color: #000000;">et les supprimer par la suite serait pertinent</span>

</td><td style="width: 50%;">![](https://wiki.uniksim.com/uploads/images/gallery/2025-06-Jun/scaled-840-0/image-1749564535687.png)

![](https://wiki.uniksim.com/uploads/images/gallery/2025-06-Jun/scaled-840-0/image-1749564724487.png)

![](https://wiki.uniksim.com/uploads/images/gallery/2025-06-Jun/scaled-840-0/image-1749571223553.png)

</td></tr><tr style="height: 151px;"><td style="width: 50%; height: 151px;">##### L'ajout de produit :

Vérifier que l'ajout de code d'activation fonctionne bien. Ceci devrait ajouter un ou des produits sur la liste en conséquence

Vérifier aussi <span style="color: #ff0000;">les cas d'échecs</span>

- Mauvais code
- Code existant

<span style="color: #000000;">\*note: Un test de ressources et de simulation démo seront vu ci-dessous. Ajouter un produit enseignant à cet étape serait pratique pour vous</span>

</td><td style="width: 50%; height: 151px;">![](https://wiki.uniksim.com/uploads/images/gallery/2025-06-Jun/scaled-840-0/image-1749563047889.png)

![](https://wiki.uniksim.com/uploads/images/gallery/2025-06-Jun/scaled-840-0/image-1749564099162.png)

</td></tr><tr><td style="width: 50%;">##### Jouer à la simulation :

Vérifier que les produits fonctionnent bien en cliquant dessus. Ceci inclus:

- Professeur
- Étudiant - En Démo
- Professeur - En Démo
- Étudiant

<span style="color: #000000;">Ceci devrait Créer un *token* <span style="color: #333333;">(dans Cookies) lors de l'ouverture, puis il</span></span><span style="color: #000000;"> devrait supprimer *le token* <span style="color: #333333;">(dans Cookies) lorsqu'il appuie sur ***Sauvegarder et quitter***</span></span>

<span style="color: #000000;">\*note: Le bouton <span style="color: #333333;">***Sauvegarder et quitter*** ferme votre connexion</span></span>

<span style="color: #000000;"><span style="color: #333333;">\*\*note: Il n'est pas nécessaire d'approfondir l'utilisation de la simulation. Juste pouvoir l'ouvrir est suffisant. Quelques fonctionnalités seront testées avec le rôle en ***True Admin*** plus bas</span></span>

</td><td style="width: 50%;">![](https://wiki.uniksim.com/uploads/images/gallery/2025-06-Jun/scaled-840-0/image-1749564099162.png)

![](https://wiki.uniksim.com/uploads/images/gallery/2025-06-Jun/scaled-840-0/image-1749565951344.png)

![](https://wiki.uniksim.com/uploads/images/gallery/2025-06-Jun/scaled-840-0/image-1749571112793.png)

![](https://wiki.uniksim.com/uploads/images/gallery/2025-06-Jun/scaled-840-0/image-1749571517295.png)

</td></tr><tr style="height: 306px;"><td style="width: 50%; height: 306px;">##### La liste des produits :

Vérifier que tous les produits sont bien présents. Faites particulièrement attention à l'ajout de *Démo*

</td><td style="width: 50%; height: 306px;">![](https://wiki.uniksim.com/uploads/images/gallery/2025-06-Jun/scaled-840-0/image-1749562704138.png)

</td></tr><tr><td style="width: 50%;">##### L'affichage des ressources :

Vérifier que le bouton ***Ressources*** fonctionne et que ses liens fonctionnent aussi

Vérifier également les options offertes :

- Copier/Coller
- Les documents téléchargeables
- Les changements des icônes dépendant des cas

</td><td style="width: 50%;">![](https://wiki.uniksim.com/uploads/images/gallery/2025-06-Jun/scaled-840-0/image-1749568884060.png)

</td></tr><tr style="height: 167px;"><td style="width: 50%; height: 167px;">##### Les liens externes :

Vérifier que tous les liens en bas de page se dirigent bien sur les informations pertinentes

</td><td style="width: 50%; height: 167px;">![](https://wiki.uniksim.com/uploads/images/gallery/2025-06-Jun/scaled-840-0/image-1749563156390.png)

![](https://wiki.uniksim.com/uploads/images/gallery/2025-06-Jun/scaled-840-0/image-1749747778376.png)

</td></tr><tr style="height: 133px;"><td style="width: 50%; height: 133px;">##### Bouton d'accueil :

Vérifier que le bouton ***Uniksim essaie, joue, apprends*** se dirige vers l'accueil des produits

</td><td style="width: 50%; height: 133px;">![](https://wiki.uniksim.com/uploads/images/gallery/2025-06-Jun/scaled-840-0/image-1749563481011.png)

</td></tr><tr style="height: 116px;"><td style="width: 50%; height: 116px;">##### Vérifier que tous les options sont présents :

Vérifier que les options sont actives pour un utilisateur régulier: ***Mes Simulations*** et ***Se déconnecter***

</td><td style="width: 50%; height: 116px;">![](https://wiki.uniksim.com/uploads/images/gallery/2025-06-Jun/scaled-840-0/image-1749565025441.png)

</td></tr><tr><td style="width: 50%;">##### Changement de language :

Vérifier que l'option de changement de langue fonctionne bien

Ceci devrait aussi garder la même langue après une déconnexion et un reconnexion

</td><td style="width: 50%;">![](https://wiki.uniksim.com/uploads/images/gallery/2025-06-Jun/scaled-840-0/image-1749564285498.png)

</td></tr><tr style="height: 363px;"><td style="width: 50%; height: 363px;">##### SignOff :

Vérifier que le bouton ***Se déconnecter*** se dirige bien vers la page d'accueil

Ceci devrait supprimer *le token* (dans LocalStorage)

</td><td style="width: 50%; height: 363px;">![](https://wiki.uniksim.com/uploads/images/gallery/2025-06-Jun/scaled-840-0/image-1749565018088.png)

![](https://wiki.uniksim.com/uploads/images/gallery/2025-06-Jun/scaled-840-0/image-1749563965558.png)

</td></tr><tr><td style="width: 50%;">##### Page Mot de passe oublié :

Vérifier que le changement de mot de passe fonctionne bien

\*note: Un email valide sera requis

</td><td style="width: 50%;">![](https://wiki.uniksim.com/uploads/images/gallery/2025-06-Jun/scaled-840-0/image-1749743858508.png)

</td></tr><tr><td style="width: 50%;">##### SignIn :

Vérifier que le bouton pour ***Se connecter*** à l'accueil du site se dirige bien à la page produit (Require: *Courriel* et *Mot de pass*)

Vérifier aussi <span style="color: #ff0000;">les cas d'échecs</span>

- Mauvaises informations

Ceci devrait créer *un token* <span style="color: #333333;">(dans LocalStorage)</span>

</td><td style="width: 50%;">![](https://wiki.uniksim.com/uploads/images/gallery/2025-06-Jun/scaled-840-0/image-1749562300722.png)

![](https://wiki.uniksim.com/uploads/images/gallery/2025-06-Jun/scaled-840-0/image-1749571216540.png)

</td></tr><tr><td style="width: 50%;">##### SignIn (chenLogin) :

Vérifier que l'ajout du lien chenLogin va directement dans une simulation

ceci requiert un compte *i+* et de pouvoir avoir un moyen de copier le lien (Cependant si vous êtes assez rapide, vous pouvez récupérer le lien directement en copiant/collant le lien 🐻)

\*uniquement la partie du code d'activation est intéressante

<span style="text-decoration: underline;">exemple de code d'activation: </span>

<p class="callout info">chenlogin?expiration=1749565644&amp;isbn=N782765065364&amp;userEmail=uniksim@gmail.com&amp;userFirstName=Nicolas&amp;userLastName=Babin&amp;expirationLicence=2043-08-31&amp;token=d29ca9f591d017fe4e9eba7c3de9318430603d7bee7e78022e1f0a77c1404a7f</p>

</td><td style="width: 50%;">![](https://wiki.uniksim.com/uploads/images/gallery/2025-06-Jun/scaled-840-0/image-1749565337890.png)

![](https://wiki.uniksim.com/uploads/images/gallery/2025-06-Jun/scaled-840-0/image-1749565448134.png)

</td></tr><tr><td style="width: 50%;">##### Les boutons de retour :

Vérifier que tous les boutons de retour de la page d'accueil fonctionnent bel et bien

</td><td style="width: 50%;">![](https://wiki.uniksim.com/uploads/images/gallery/2025-06-Jun/scaled-840-0/image-1749565532582.png)

</td></tr><tr><td style="width: 50%;">##### Les cookies :

Vérifier que les cookies (provenant de cookieYes) fonctionnent bel et bien

</td><td style="width: 50%;">![](https://wiki.uniksim.com/uploads/images/gallery/2025-06-Jun/scaled-840-0/image-1749565739026.png)

</td></tr></tbody></table>

####  

#### <span style="text-decoration: underline;">Fonctionnalité - Cas d'utilisateur admin</span>

<p class="callout info"><span style="text-decoration: underline;">Compte déjà existant</span>  
  
Courriel: <comptetestadmin01@gmail.com>  
Mot de passe: E4Vx&lt;52  
  
<span style="text-decoration: underline;">Autre</span>  
Web (admin\_user) | user : 31957  
  
\*note: Ce compte test uniquement le cas de *Uqam*</p>

<table border="1" id="bkmrk-le-r%C3%B4le-de-l%27utilis" style="border-collapse: collapse; width: 100%;"><tbody><tr><td style="width: 50%;">##### Le rôle de l'utilisateur :

Vérifier que le rôle est affiché en <span style="color: #0000ff;">bleu </span>sur le nom de l'utilisateur

</td><td style="width: 50%;">![](https://wiki.uniksim.com/uploads/images/gallery/2025-06-Jun/scaled-840-0/image-1749566351843.png)

</td></tr><tr><td style="width: 50%;">##### Vérifier que tous les options sont présents :

Vérifier que les options sont actives pour un utilisateur admin: ***Mes Simulations***, ***Admin*** et ***Se déconnecter***

</td><td style="width: 50%;">![](https://wiki.uniksim.com/uploads/images/gallery/2025-06-Jun/scaled-840-0/image-1749566412204.png)

</td></tr><tr><td style="width: 50%;">##### La page admin :

Vérifier que seulement une partie de la page admin est affichée. Ceci inclus:

- Le bouton de ***Se connecter***
- Pouvoir voir uniquement les enseignants et les étudiants de l'école respective
- Pouvoir jouer en tant que la personne

</td><td style="width: 50%;">![](https://wiki.uniksim.com/uploads/images/gallery/2025-06-Jun/scaled-840-0/image-1749566489253.png)

</td></tr><tr><td style="width: 50%;">##### La page admin (filtre) :

Vérifier que tous les filtres fonctionnes

</td><td style="width: 50%;">![](https://wiki.uniksim.com/uploads/images/gallery/2025-06-Jun/scaled-840-0/image-1749566489253.png)

</td></tr><tr><td style="width: 50%;">##### Changement de language :

Vérifier que l'option de changement de langue fonctionne bien

Ceci devrait aussi garder la même langue après une déconnexion et un reconnexion

</td><td style="width: 50%;">![](https://wiki.uniksim.com/uploads/images/gallery/2025-06-Jun/scaled-840-0/image-1749566937483.png)

</td></tr></tbody></table>

####  

#### <span style="text-decoration: underline;">Fonctionnalité - Cas d'utilisateur true admin</span>

<table border="1" id="bkmrk-%C2%A0-%C2%A0" style="border-collapse: collapse; width: 100%; height: 3476px;"><tbody><tr style="height: 116px;"><td style="width: 50%; height: 116px;">##### Le rôle de l'utilisateur :

Vérifier que le rôle est affiché en <span style="color: #ff6600;">orange</span> sur le nom de l'utilisateur

</td><td style="width: 50%; height: 116px;">![](https://wiki.uniksim.com/uploads/images/gallery/2025-06-Jun/scaled-840-0/image-1749567424207.png)

</td></tr><tr style="height: 232px;"><td style="width: 50%; height: 232px;">##### La désactivation de produit :

Vérifier que la suppression de produit sous ![](https://wiki.uniksim.com/uploads/images/gallery/2025-06-Jun/scaled-840-0/image-1749567278536.png)et ***Désactivé*** se fait bien

Ceci devrait uniquement rendre le produit non actif

</td><td style="width: 50%; height: 232px;">![](https://wiki.uniksim.com/uploads/images/gallery/2025-06-Jun/scaled-840-0/image-1749567169594.png)

</td></tr><tr style="height: 285px;"><td style="width: 50%; height: 285px;">##### La page admin :

Vérifier que tous les options sont disponible. Cela inlus :

- Le bouton de ***Se connecter*** (*Game*, *Alpha* et *Demo*)
- Prendre le courriel de jeu de la personne
- Pouvoir ***Renouveler*** son *GameOid*
- Pouvoir voir tous les utilisateurs
- Pouvoir jouer en tant que la personne

</td><td style="width: 50%; height: 285px;">![](https://wiki.uniksim.com/uploads/images/gallery/2025-06-Jun/scaled-840-0/image-1749567544181.png)

</td></tr><tr style="height: 442px;"><td style="width: 50%; height: 442px;">##### La page user :

Vérifier que tous les informations sont présentés. Cela **<span style="text-decoration: underline;">peut</span>** inclure :

- À Propos (Toujours)
- Tous les Simulations
- Tous les Teams étudiants
- Options

Vérifier aussi <span style="color: #ff0000;">les cas d'échecs </span>(si possible)

- Server down
- Pas d'information

\*note: Il est nécessaire de tester ce cas sur plusieurs utilisateurs différents, car ils ont chacun des cas distincts

<span style="color: #ff00ff;"><span style="text-decoration: underline;"><span style="color: #000000; text-decoration: underline;">Requis:</span></span> Brainlcloud</span>

</td><td style="width: 50%; height: 442px;">![](https://wiki.uniksim.com/uploads/images/gallery/2025-06-Jun/scaled-840-0/image-1749572135073.png)

</td></tr><tr style="height: 593px;"><td style="width: 50%; height: 593px;">##### La page user (Tous les teams étudiants) :

Vérifier que l'élément est bien chargé après un clic

Vérifier aussi <span style="color: #ff0000;">les cas d'échecs </span>(si possible)

- Server down

<span style="color: #ff00ff;"><span style="text-decoration: underline;"><span style="color: #000000; text-decoration: underline;">Requis:</span></span> Brainlcloud</span>

</td><td style="width: 50%; height: 593px;">![](https://wiki.uniksim.com/uploads/images/gallery/2025-06-Jun/scaled-840-0/image-1749576569419.png)

![](https://wiki.uniksim.com/uploads/images/gallery/2025-06-Jun/scaled-840-0/image-1749576666774.png)

</td></tr><tr style="height: 298px;"><td style="width: 50%; height: 298px;">##### La page user (Options) :

Vérifier que le copySim fonctionne bien sur différents cas

- Étudiant =­&gt; Live à Dev
- Prof =&gt; Live à Dev
- Prof =&gt; Dev à Dev2
- Un utilisateur qui n'a pas de simulation copiée
- etc.

Vérifier aussi <span style="color: #ff0000;">les cas d'échecs </span>(si possible)

- Server down

<span style="color: #ff00ff;"><span style="text-decoration: underline;"><span style="color: #000000; text-decoration: underline;">Requis:</span></span> Brainlcloud</span>

</td><td style="width: 50%; height: 298px;">![](https://wiki.uniksim.com/uploads/images/gallery/2025-06-Jun/scaled-840-0/image-1749576710084.png)

</td></tr><tr style="height: 265px;"><td style="width: 50%; height: 265px;">##### Jouer à la simulation :

Vérifier que les simulations sont disponibles pour être lancées sur différentes *Braincloud*. Ceci inclus :

- Live
- Alpha
- Demo

<span style="color: #000000;"><span style="color: #333333;">\*note: Il n'est pas nécessaire d'approfondir l'utilisation du jeu. Juste pouvoir l'ouvrir est suffisant.</span></span>

</td><td style="width: 50%; height: 265px;">![](https://wiki.uniksim.com/uploads/images/gallery/2025-06-Jun/scaled-840-0/image-1749744466674.png)

</td></tr><tr style="height: 313px;"><td style="width: 50%; height: 313px;">##### La page commentaire :

Vérifier que le filtre et les informations sont disponibles

Vérifier aussi <span style="color: #ff0000;">les cas d'échecs </span>(si possible)

- Server down

<span style="color: #ff00ff;"><span style="text-decoration: underline;"><span style="color: #000000; text-decoration: underline;">Requis:</span></span> Brainlcloud</span>

</td><td style="width: 50%; height: 313px;">![](https://wiki.uniksim.com/uploads/images/gallery/2025-06-Jun/scaled-840-0/image-1749577093856.png)

</td></tr><tr style="height: 317px;"><td style="width: 50%; height: 317px;">##### La page actives :

Vérifier que le filtre et les informations sont disponibles

Vérifier aussi <span style="color: #ff0000;">les cas d'échecs </span>(si possible)

- Server down

<span style="color: #ff00ff;"><span style="text-decoration: underline;"><span style="color: #000000; text-decoration: underline;">Requis:</span></span> Brainlcloud</span>

</td><td style="width: 50%; height: 317px;">![](https://wiki.uniksim.com/uploads/images/gallery/2025-06-Jun/scaled-840-0/image-1749577152445.png)

</td></tr><tr style="height: 284px;"><td style="width: 50%; height: 284px;">##### La page paramètre :

Vérifier l'ajout d'un nouveau code produit. (Préférablement un code professeur)

\*Cela inclut l'activation du produit

\*note: Chaque ajout de code de produit se fait immédiatement créer sur le SQL. Veuillez créer des codes avec modération pour ne pas surcharger le SQL de code produit.

</td><td style="width: 50%; height: 284px;">![](https://wiki.uniksim.com/uploads/images/gallery/2025-07-Jul/scaled-840-0/image-1751984218007.png)

</td></tr><tr style="height: 331px;"><td style="width: 50%; height: 331px;">##### Options de changement de serveur :

Vérifier que le changement de serveur *Braincloud* se fait bien. Pour cela, il sera nécessaire de refaire toutes les étapes qui requièrent <span style="color: #ff00ff;">Brainlcloud</span>

Ceci devrait créer *un currentBraincloud* <span style="color: #333333;">(dans LocalStorage)</span>

<span style="color: #000000;">\*note: Certaines données ne pourront pas être disponibles, puisque l'affichage de la liste est selon la base de données de *Live*</span>

</td><td style="width: 50%; height: 331px;">![](https://wiki.uniksim.com/uploads/images/gallery/2025-06-Jun/scaled-840-0/image-1749577195455.png)

</td></tr></tbody></table>

####  

#### <span style="text-decoration: underline;">Fonctionnalité - Cas d'utilisateur true admin (Unity)</span>

<p class="callout info">Il faudra se connecter en tant qu'un utilisateur ***Alpha***</p>

<table border="1" id="bkmrk-%C2%A0-%C2%A0-0" style="border-collapse: collapse; width: 100%;"><tbody><tr><td style="width: 50%;">##### Téléchargement Excel :

Vérifier que le téléchargement d'Excel fonctionne bien

\*note: Les données peuvent ne pas s'afficher directement. Activer les modifications

</td><td style="width: 50%;">![](https://wiki.uniksim.com/uploads/images/gallery/2025-06-Jun/scaled-840-0/image-1749737609548.png)

![](https://wiki.uniksim.com/uploads/images/gallery/2025-06-Jun/scaled-840-0/image-1749744831550.png)

</td></tr><tr><td style="width: 50%;">##### Classement détaillé :

Vérifier que l'onglet ***Classement détaillé*** fonctionne bien sur toutes les sélections

\*note: Il serait nécessaire de vérifier sur plusieurs simulations si certaines données ne sont pas disponibles

</td><td style="width: 50%;">![](https://wiki.uniksim.com/uploads/images/gallery/2025-06-Jun/scaled-840-0/image-1749737797746.png)

</td></tr><tr><td style="width: 50%;">##### Téléchargement PDF :

Vérifier que le téléchargement de PDF fonctionne bien

\*note: Il serait recommandé de vérifier sur plusieurs *pièces justificatives*

</td><td style="width: 50%;">![](https://wiki.uniksim.com/uploads/images/gallery/2025-06-Jun/scaled-840-0/image-1749738192085.png)

</td></tr></tbody></table>

# Compte test - Création de compte

#### <span style="text-decoration: underline;">Liste de tous les comptes créé pour tester la création de compte</span>

<table border="1" id="bkmrk-email-password-test1" style="border-collapse: collapse; width: 100%; height: 198px;"><tbody><tr style="height: 68px;"><td style="width: 50%; height: 68px;">##### Email

</td><td style="width: 50%; height: 68px;">##### Password

</td></tr><tr style="height: 31px;"><td style="width: 50%; height: 31px;">test1234@gmail.com</td><td style="width: 50%; height: 31px;">`J8,1r6f5z`\\</td></tr><tr style="height: 37px;"><td style="width: 50%; height: 37px;"><test123@gmail.com></td><td style="width: 50%; height: 37px;"> </td></tr><tr style="height: 31px;"><td style="width: 50%; height: 31px;">test546.uniksim@gmail.com</td><td style="width: 50%; height: 31px;">9\*H0wi}N5Mh9</td></tr><tr style="height: 31px;"><td style="width: 50%; height: 31px;">test123456@gmail.com</td><td style="width: 50%; height: 31px;">9\*H0wi}N5Mh9</td></tr><tr><td style="width: 50%;">test12345@test.com</td><td style="width: 50%;"> </td></tr><tr><td style="width: 50%;">ll.uniksim.test987@gmail.com</td><td style="width: 50%;">8q7Z34sw3\[\]j</td></tr><tr><td style="width: 50%;">test555@test.com</td><td style="width: 50%;">@d\*44V$"u:94</td></tr><tr><td style="width: 50%;">fahira8491@2insp.com</td><td style="width: 50%;">vm9fuZvk5GML9aH3bbmT</td></tr><tr><td style="width: 50%;">UrsusTempMailToTest123456@account.xn--yaho-sqa.com</td><td style="width: 50%;"> @testpasword</td></tr></tbody></table>

# Local database (PHPMyAdmin) - Conflict

##### <span style="text-decoration: underline;">Local database (PHPMyAdmin) - Conflict</span>

- Si vous avez une erreur comme ci-dessous avec **XAMPP**, suivez les fixs de cette vidéo : [https://www.youtube.com/watch?v=OEUVth2Av48](https://www.youtube.com/watch?v=OEUVth2Av48) (Généralement, le dossier backup fix l'erreur "0:41")![](https://wiki.uniksim.com/uploads/images/gallery/2025-07-Jul/scaled-840-0/image-1751550601975.png)
- Si vous avez cette erreur en utilisant XAMPP :  
    ![](https://wiki.uniksim.com/uploads/images/gallery/2025-07-Jul/scaled-840-0/image-1751550666487.png)
    
    
    - Faire une suppression de toute Cookies et de LocalStorage
- Si vous ne trouvez pas l'option **drop database** ![](https://wiki.uniksim.com/uploads/images/gallery/2025-07-Jul/scaled-840-0/image-1751550794173.png)
    
    
    - Suivre les méthode de ce lien : [https://stackoverflow.com/questions/4410630/phpmyadmin-enable-drop-database-statement](https://stackoverflow.com/questions/4410630/phpmyadmin-enable-drop-database-statement)
        - En bref: Ajouter `$cfg['AllowUserDropDatabase'] = true;` dans *phpMyAdmin(config.inc.php)* sous XAMPP (Ceci se trouve dans Apache­&gt;Config)

# Build Unity en local

##### <span style="text-decoration: underline;">Note:</span>

Avant de commencer, vérifiez que votre **Unity** est bien mis en place (aucun crash, aucune erreur, stable, etc.) puisque le *Build* prend du temps (en moyenne 5-7 minutes, dépendamment de l'ordinateur).

<span style="color: #999999;">*<sub>Ignorer cette étape si votre ordinateur fait partie des top 1 pour build 🚀</sub>*</span>

##### <span style="text-decoration: underline;">Unity:</span>

1. Avec les touches `CTRL + SHIFT + B`, vous devez avoir les paramètres suivants sur Unity ![](https://wiki.uniksim.com/uploads/images/gallery/2025-07-Jul/scaled-840-0/image-1752175559515.png)
2. Regarder la version de votre **Unity** dans le fichier `version.txt` (situé à "Assets/Ressources/data/version.txt"). ![](https://wiki.uniksim.com/uploads/images/gallery/2025-07-Jul/scaled-840-0/image-1752175858581.png)
    
    ![](https://wiki.uniksim.com/uploads/images/gallery/2025-07-Jul/scaled-840-0/image-1752175870921.png)
3. Changer la version du build dans la version locale du backend en web (Dans le fichier `constantsVariable.js`).
    
    ![](https://wiki.uniksim.com/uploads/images/gallery/2025-07-Jul/scaled-840-0/image-1752176028370.png)
    
    
    - Changer : `LOCAL_WEBGL_VERSION: {votre version}`
4. Changer la version du build dans la version locale du database (Situé dans constants)
    
    ![](https://wiki.uniksim.com/uploads/images/gallery/2025-07-Jul/scaled-840-0/image-1752176314611.png)
5. Une fois le build de Unity terminé, mettre les fichiers du build dans le frontend (Dans le dossier `uniksimFrontEnd\src\assets\unity\Build`) ![](https://wiki.uniksim.com/uploads/images/gallery/2025-07-Jul/scaled-840-0/image-1752176698497.png)
    
    ![](https://wiki.uniksim.com/uploads/images/gallery/2025-07-Jul/scaled-840-0/image-1752176715817.png)
    
    
    - Il est important que les fichiers soit les mêmes (Type et nom)
    - Il est aussi possible de modifier les fichiers du backend directement dans front, mais il n'est pas recommandé de le faire sachant qu'un build du frontend écrasera le build et que les versions seront erronées.
6. Faire un build du frontend ![](https://wiki.uniksim.com/uploads/images/gallery/2025-07-Jul/scaled-840-0/image-1752176841740.png)
7. Tester 🥳

##### <span style="text-decoration: underline;">Erreurs courantes:</span>

- Si vous avez : ![](https://wiki.uniksim.com/uploads/images/gallery/2025-07-Jul/scaled-840-0/image-1752176374182.png)
    
    
    - Une des versions de votre build (en backend ou en database) ne correspond pas. Veuillez revoir les étapes 3 et 4.