Web

Support et IA

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.

Support et IA

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.

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

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.

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

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

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.

Fichiers principaux

Points d’attention

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.

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

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.

Support et 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é

Responsabilité Compte : /account Support : /support
Backend AccountGateway + PresenceService SupportGateway + SupportService
Frontend AccountSocketService SupportSocketService
Événements reçus user.status, user.presence, admin.status, notification.created message.created, ticket.updated, typing
Actions émises updateStatus, updateTelemetry, updateGamePresence joinConversation, leaveConversation, typing, checkOnline

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.

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 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é.

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.

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

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.

Architecture générale

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

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

Flux typique d’une requête Web

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 et 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

Points d’entrée essentiels

Architecture générale

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

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

Backend : uniksim-back-end

Où commencer selon le besoin

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

Architecture générale

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

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 :

Couche historique / auxiliaire

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

Quand utiliser quelle couche

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

Avant de refactorer

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.

Architecture générale

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

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

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

Serveurs et API

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

Serveurs et API

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.

Assemblage du backend

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

Contrôleurs importants

Serveurs et API

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

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.

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 :

Flux d’une commande Admin Server

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

Serveurs et API

Authentification et guards

Vue d’ensemble

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

Backend

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.

Serveurs et API

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

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.

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

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).

Serveurs et API

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

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 :

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 :

Redis

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

Choisir le bon stockage

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

É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.

Serveurs et API

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

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

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

Points d’attention

Serveurs et API

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 :

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

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 :

Uploads du support

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

Sécurité des fichiers

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

Frontend Angular

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

Frontend Angular

Structure et routing Angular

Structure principale

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

Module racine

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

Familles de routes

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.

Frontend Angular

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

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 :

Accès aux données et APIs

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

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 :

Notifications

service/notifications/ contient notamment :

Présence et WebPanel

Choisir où placer une nouvelle logique

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

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.

Frontend Angular

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

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 :

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

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

Frontend Angular

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.

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.

Valeur interne Vue affichée
null Panel fermé.
notifications Centre de notifications.
chat Support Web UnikBot : app-page-support en mode compact.

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 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 :

Action API Web
Charger la liste GET /notifications
Marquer comme lu POST /notifications/:uid/read avec isRead
Supprimer DELETE /notifications/:uid

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 pour la réception serveur, l'inbox et le push.

Fichiers à modifier

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

Vérifier une modification

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.

Intégrations et systèmes transversaux

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

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 :

Flux heartbeat

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 :

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

Points d’attention

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.

Intégrations et systèmes transversaux

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

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.

Action Endpoint Comportement
Charger GET /notifications Retourne l’inbox du compte authentifié.
Lu / non lu POST /notifications/:notificationUid/read Met à jour l’entrée par UID avec LSET.
Supprimer DELETE /notifications/:notificationUid Retire l’entrée avec LREM.

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

Voir aussi Support temps réel.

Intégrations et systèmes transversaux

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

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 :

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 :

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 :

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.

Comment diagnostiquer une intégration

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

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.

Site Uniksim (Old)

Note uniksimWeb

Les versions utilisées sur le site :

Angular / NodeJs compatibilité : Lien

Changer de version avec nvm (Node Version Manager) : nvm use *version

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!

Node version : node -v

Angular version : ng version

NestJs version : nest --version

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

 

Note : Le fichier package.json possède toutes les versions

Note : Ne pas oublier de faire un npm install dans backendEnd et frontEnd

Les imports importants NestJs :
  • TypeOrmModule : Communication et conversion des données avec la mySql (Query)
  • DatabaseProviders : Connection avec mySql
  • 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é)

Pour plus de détails voir : app.module.ts ou package.json

Les roles :
  • 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

*note: Il existe un role superAdmin, mais cela n'est pas vraiment utilisé...

DigitalOcean (Update branch) :

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)

  1. Dans la section, Droplets, puis le dossier du site en question

    image-1723218630153.png

  2. Ensuite dans Console

    image-1723218747353.png

    • Vous devriez voir une console en linux pour faire les modifications
  3. Naviguer à travers les fichiers pour trouver le dossier recherché

    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.

      image-1723220094918.png

      • Faire la commande suivante si c'est le cas (forge fait référence au username, changer selon le cas)
        • su - forge

  4. Utiliser les commandes nécessaire à vos changements
    • Remettre à l'état d'origine le dossier
      • git reset .

      • git reset --hard

        • git reset --hard risque de nécessiter origin/master comme paramètre
    • Récupérer la branch commit
      • git pull

    • Aller vers la branche
      • git checkout

    • Voir l'état de la branche actuel
      • git status

    • Similaire à reset, elle permet de retirer les dossiers non nécessaires
      • git clean -fd

  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
Cookieyes :

Url : https://app.cookieyes.com/

Script url : https://cdn-cookieyes.com/client_data/b08568c123e8efb0b38c9ce6/script.js

Build :

ng build

Notes :
Problèmes :
Les références de création :
Site Uniksim (Old)

Update/Deploy dans Angular (old)

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

Tous les étapes se font sur Visual Studio Code

1) Se déplacer au bon dossier :

cd {uniksim}/frontend/angular

2) Build Angular :

ng build

3) Modifier le angular.blade.php :

Situé à {uniksim}/resources/views/angular.blade.php

@extends('layouts.app')

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

@section('applink')

@stop

@section('content')

@endsection

Site Uniksim (Old)

Debug en Web frontEnd

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

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

  1. Activer le site sous Launch Frontend and Backend (dev)

    image-1737987681718.png

  2. Vérifier que tout soit en marche :
    1. Sur le frontEnd vous devriez avoir

      image-1737987924592.png

    2. Sur le backend vous devriez avoir (les messages peuvent varier d'ordre)

      image-1737987937603.png

  3.  

    Ouvrir une session localhost:4200 web

    image-1737988787389.png

  4. Sous Sources­­>Page>webpack://>login>login.component.ts

    image-1737988840380.png

  5. Mettre des points d'arrêts sur la requête attendu

    image-1737989003122.png

    image-1737989034392.png

  6. Envoyer la requête, vous devriez commencé à débugger

    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)

 

Site Uniksim (Old)

Test de fonctionnalité complète

*note: Les tests ci-dessous sont déjà dans un ordre pour simplifier les tests. Cependant, beaucoup de déconnexions seront requises

Fonctionnalité - Cas d'utilisateur normal

Register :

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

 

Vérifier aussi les cas d'échecs

  • 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

Ceci devrait créer un token (dans LocalStorage)

 

*note: Si ceci est fait sur le site Live ou Dev, veuillez l'ajouter sur Compte test - Création de compte (Se trouvant sur le Wiki) et les supprimer par la suite serait pertinent

 

image-1749564535687.png

image-1749564724487.png

image-1749571223553.png

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 les cas d'échecs

  • Mauvais code
  • Code existant

 

*note: Un test de ressources et de simulation démo seront vu ci-dessous. Ajouter un produit enseignant à cet étape serait pratique pour vous

image-1749563047889.png

image-1749564099162.png

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

Ceci devrait Créer un token (dans Cookies) lors de l'ouverture, puis il devrait supprimer le token (dans Cookies) lorsqu'il appuie sur Sauvegarder et quitter

 

*note: Le bouton Sauvegarder et quitter ferme votre connexion

 

**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

 

image-1749564099162.png

image-1749565951344.png

image-1749571112793.png

image-1749571517295.png

La liste des produits :

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

 

image-1749562704138.png

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

 

image-1749568884060.png

Les liens externes :

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

 

image-1749563156390.png

image-1749747778376.png

Bouton d'accueil :

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

 

image-1749563481011.png

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

 

image-1749565025441.png

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

 

image-1749564285498.png

SignOff :

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

 

Ceci devrait supprimer le token (dans LocalStorage)

 

image-1749565018088.png

image-1749563965558.png

Page Mot de passe oublié :

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

 

*note: Un email valide sera requis

 

image-1749743858508.png

 

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 les cas d'échecs

  • Mauvaises informations

Ceci devrait créer un token (dans LocalStorage)

 

image-1749562300722.png

image-1749571216540.png

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

 

exemple de code d'activation:

chenlogin?expiration=1749565644&isbn=N782765065364&userEmail=uniksim@gmail.com&userFirstName=Nicolas&userLastName=Babin&expirationLicence=2043-08-31&token=d29ca9f591d017fe4e9eba7c3de9318430603d7bee7e78022e1f0a77c1404a7f

 

image-1749565337890.png

image-1749565448134.png

Les boutons de retour :

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

 

image-1749565532582.png

Les cookies :

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

 

image-1749565739026.png

 

Fonctionnalité - Cas d'utilisateur admin

Compte déjà existant

Courriel: comptetestadmin01@gmail.com
Mot de passe: E4Vx<52

Autre
Web (admin_user) | user : 31957

*note: Ce compte test uniquement le cas de Uqam

Le rôle de l'utilisateur :

Vérifier que le rôle est affiché en bleu sur le nom de l'utilisateur

 

image-1749566351843.png

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

 

image-1749566412204.png

 

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

 

image-1749566489253.png

 

La page admin (filtre) :

Vérifier que tous les filtres fonctionnes

 

image-1749566489253.png

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

 

image-1749566937483.png

 

Fonctionnalité - Cas d'utilisateur true admin

Le rôle de l'utilisateur :

Vérifier que le rôle est affiché en orange sur le nom de l'utilisateur

 

image-1749567424207.png

La désactivation de produit :

Vérifier que la suppression de produit sous image-1749567278536.pnget Désactivé se fait bien

 

Ceci devrait uniquement rendre le produit non actif

 

image-1749567169594.png

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

 

image-1749567544181.png

La page user :

Vérifier que tous les informations sont présentés. Cela peut inclure :

 

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

Vérifier aussi les cas d'échecs (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

 

Requis: Brainlcloud

 

image-1749572135073.png

La page user (Tous les teams étudiants) :

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

 

Vérifier aussi les cas d'échecs (si possible)

  • Server down

Requis: Brainlcloud

 

image-1749576569419.png

image-1749576666774.png

La page user (Options) :

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

  • Étudiant =­> Live à Dev
  • Prof => Live à Dev
  • Prof => Dev à Dev2
  • Un utilisateur qui n'a pas de simulation copiée
  • etc.

Vérifier aussi les cas d'échecs (si possible)

  • Server down

Requis: Brainlcloud

 

image-1749576710084.png

Jouer à la simulation :

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

  • Live
  • Alpha
  • Demo

*note: Il n'est pas nécessaire d'approfondir l'utilisation du jeu. Juste pouvoir l'ouvrir est suffisant.

 

image-1749744466674.png

La page commentaire :

Vérifier que le filtre et les informations sont disponibles

 

Vérifier aussi les cas d'échecs (si possible)

  • Server down

Requis: Brainlcloud

 

image-1749577093856.png

La page actives :

Vérifier que le filtre et les informations sont disponibles

 

Vérifier aussi les cas d'échecs (si possible)

  • Server down

Requis: Brainlcloud

 

image-1749577152445.png

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.

 

 

image-1751984218007.png

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 Brainlcloud

 

Ceci devrait créer un currentBraincloud (dans LocalStorage)

 

*note: Certaines données ne pourront pas être disponibles, puisque l'affichage de la liste est selon la base de données de Live

 

image-1749577195455.png

 

Fonctionnalité - Cas d'utilisateur true admin (Unity)

Il faudra se connecter en tant qu'un utilisateur Alpha

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

 

image-1749737609548.png

image-1749744831550.png

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

 

image-1749737797746.png

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

 

image-1749738192085.png

Site Uniksim (Old)

Compte test - Création de compte

Liste de tous les comptes créé pour tester la création de compte

Email
Password
test1234@gmail.com `J8,1r6f5z`\
test123@gmail.com  
test546.uniksim@gmail.com 9*H0wi}N5Mh9
test123456@gmail.com 9*H0wi}N5Mh9
test12345@test.com  
ll.uniksim.test987@gmail.com 8q7Z34sw3[]j
test555@test.com @d*44V$"u:94
fahira8491@2insp.com vm9fuZvk5GML9aH3bbmT
UrsusTempMailToTest123456@account.xn--yaho-sqa.com  @testpasword
Site Uniksim (Old)

Local database (PHPMyAdmin) - Conflict

Local database (PHPMyAdmin) - Conflict
Site Uniksim (Old)

Build Unity en local

Note:

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).

Ignorer cette étape si votre ordinateur fait partie des top 1 pour build 🚀

Unity:
  1. Avec les touches CTRL + SHIFT + B, vous devez avoir les paramètres suivants sur Unity

    image-1752175559515.png

  2. Regarder la version de votre Unity dans le fichier version.txt (situé à "Assets/Ressources/data/version.txt").

    image-1752175858581.png

    image-1752175870921.png

  3. Changer la version du build dans la version locale du backend en web (Dans le fichier constantsVariable.js).

    image-1752176028370.png

    • Changer : LOCAL_WEBGL_VERSION: {votre version}
  4. Changer la version du build dans la version locale du database (Situé dans constants)

    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)

    image-1752176698497.png

    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

    image-1752176841740.png

  7. Tester 🥳
Erreurs courantes: