Web
- Support et IA
- Architecture générale
- Vue d’ensemble du système Web
- Structure des projets et dossiers
- Frontières entre code moderne et legacy
- Ajouter une fonctionnalité Web de bout en bout
- Serveurs et API
- Serveur principal NestJS
- Administration : API NestJS et Admin Server Express
- Authentification et guards
- Configuration, environnements et constantes
- Base de données et persistance
- Build et déploiement Web
- Conventions de sécurité Web
- Frontend Angular
- Structure et routing Angular
- Services Angular et communication avec l’API
- Pages, composants et structure UI
- Panel Web — interface superposée au jeu et intégration Unity
- Intégrations et systèmes transversaux
- Site Uniksim (Old)
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_PROVIDERetAI_EMBEDDING_MODELrestent 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.
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.
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
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.
- 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.tsuniksim-back-end/src/service/ai.service.tsuniksim-back-end/src/node.js/server/ai/server.jsuniksim-back-end/src/embedding/ingest.jsserver/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.
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
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 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
- L’interface envoie le message et la pièce jointe par HTTP.
SupportServicevalide la conversation et la pièce jointe puis sauvegarde le message USER.MESSAGE_CREATEDest émis; le gateway mappe le message avecSupportMapper.toMessageDtoet diffusemessage.createdvers sa conversation.- 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
- 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.tsetsupport-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
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
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
uniksimFrontEnd/src/main.tsuniksimFrontEnd/src/app/app.module.tsuniksim-back-end/src/main.tsuniksim-back-end/src/app.module.tsuniksim-back-end/src/app.controller.tsuniksim-back-end/src/database.providers.tsuniksim-back-end/src/node.js/server/constantsVariable.jsuniksim-back-end/src/node.js/server/admin_server.jsuniksim-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
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 dansapp.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.jsou 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.tspour le compte,gateway/support.gateway.tspour le support,guards/socketAuth.middleware.tspour leur authentification commune. - Notifications :
service/notification.service.tsest le pipeline générique;service/game-notification.service.tsvalide le destinataire du jeu;dto/notification.dto.tsdé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 dansModels/Notification.tsetModels/Presence.ts. - IA :
node.js/server/ai/contract/,factory/,guard/,usage/etprovider/gemini/. Le SDK Vertex et son adaptation restent dans le provider. - Tests backend :
test/ai/ettest/notification/; configuration partagéetest/jest.config.cjs, configuration IAtest/jest.ai.config.cjs. Exécuternpm test -- --runInBandounpm run test:aidepuis 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
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.tspour les endpoints;service/*.service.tspour 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
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,NodeJsUtilsouNodeJsBackendBraincloudinitialisés dansdatabase.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
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
- Définir l’action utilisateur, les données entrantes/sortantes, le niveau d’accès et le type de persistance.
- Côté Angular, placer l’écran dans
Pages/ou le composant dansComponents/, puis passer par un service Angular pour les appels backend. - Ajouter ou réutiliser la route dans
app.module.tset appliquer le guard frontend adapté. - Côté backend, ajouter l’endpoint au controller logique existant. Garder le controller mince.
- Placer la logique métier dans
src/service/. - 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à.
- Ajouter Socket.IO/EventEmitter seulement si la mise à jour doit être temps réel.
- Appliquer le guard backend approprié et valider les IDs et permissions côté serveur.
- Centraliser les paramètres dans
constantsVariable.jsou les fichiers.env. - 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
- 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
aiServerReadyavant 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 :
- les routes d’administration de l’API NestJS principale, protégées par des guards et reliées aux services backend;
- un serveur Express d’administration séparé dans
uniksim-back-end/src/node.js/server/admin_server.js, qui écoute localement sur le port8105et 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.
AdminUserControllersous/admin: récupération et gestion d’informations utilisateurs.AdminPresenceControllersous/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
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.tsuniksim-back-end/src/app.module.tsuniksim-back-end/src/node.js/server/admin_server.jsuniksim-back-end/src/node.js/server/constantsVariable.jsuniksim-back-end/src/service/admin.service.tsuniksim-back-end/src/service/adminUser.service.tsuniksim-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.
AuthGuardUserprotège les endpoints utilisateur.AuthGuardGameprotège les endpoints consommés par le jeu.AuthGuardAdminetAuthGuardAdminUserprotè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
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.HOSTNAMEConstantsInUse.PORTSConstantsInUse.USERNAMEConstantsInUse.PASSWORD_DATABASEConstantsInUse.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,RoleUserProduct,ProductsCode,ProductsResources,ResourcesPeriod,ConstantSupportConversation,SupportTicket,SupportMessageUserFcmToken
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
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: truesur 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.
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 :
- Se connecter au serveur DigitalOcean.
- Passer sur l’utilisateur
forgeavecsudo -u forgeou la commande équivalente utilisée sur le serveur. - Aller dans le dossier du site avec
cd sim.dev.uniksim.com. - Mettre le code à jour.
- Builder le frontend Angular avec
npm run builddansuniksimFrontEnd. - Builder le backend NestJS avec
npm run builddansuniksim-back-end. - 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
npm run build: compile NestJS.npm run start:dev: démarredist/mainavecdev.env.npm run start:dev2: démarre avecdev2.env.npm run start:demo: démarre avecdemo.env.npm run start:live: démarre aveclive.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/frontavant le build backend. - Vérifier l’environnement utilisé avant de lancer le serveur :
demo,dev,dev2oulive.
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
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-Securityest 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.basenameet 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
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
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 dansapp.module.ts.
Accès aux données et APIs
service/requestAndData/ contient les services historiques de communication et de données :
braincloudRequest.service.tsdataBaseRequest.service.tsdataSource.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
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.
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 :
PageLogin,PageForgotPassword,PageUnauthorizedPageIndexPageWebglPageSupportetPageSupportAdminPageAdminPresencePageTableListetPageUserInformationPageSettings,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
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/ouPopup/.
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.
| 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
- 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
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
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
uniksimFrontEnd/src/app/Pages/PageWebgl/uniksimFrontEnd/src/assets/unity/uniksim-back-end/src/app.controller.ts—GameControlleruniksim-back-end/src/service/game.service.tsuniksim-back-end/src/guards/authGame.guard.tsuniksim-back-end/src/node.js/server/server.jsuniksim-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.
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]
- Vérifier que le compte destinataire existe.
- Construire l’enveloppe avec UID unique, puis sauvegarder l’inbox.
- Émettre
notification.created;AccountGatewayrelaie la notification versuser_<userId>dans le namespace/account. - 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
src/service/notification.service.ts,game-notification.service.ts,firebase.service.tssrc/dto/notification.dto.ts,src/gateway/account.gateway.ts,src/guards/socketAuth.middleware.tssrc/app.controller.tsetNOTIFICATION_CONFIGdanssrc/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.tsetgame-notification.service.test.ts
Voir aussi Support temps réel.
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 :
src/node.js/server/backend_braincloud.jssrc/node.js/server/server.jssrc/node.js/server/admin_server.jssrc/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.tssrc/service/notification.service.tsUserFcmTokendans 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.tssrc/node.js/server/ai/server.jssrc/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.
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.tssrc/mail/MailControllerdansapp.controller.ts
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
- 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
Les versions utilisées sur le site :
- Node.js v.22.5.1
- Angular v.18.2.11 (FrontEnd)
- NestJs v.11.0.11 (BackEnd)
Angular / NodeJs compatibilité : Lien
|
Changer de version avec nvm (Node Version Manager) : Voir la liste sur nvm (Node Version Manager) : Voir les packages outdated : Mettre à jour les packages (classique) : Mettre à jour les packages (avec npm-check-updates) : |
|
Node version : Angular version : NestJs version : *npm-check-updates (backendEnd) :
Note : Le fichier package.json possède toutes les versions Note : Ne pas oublier de faire un |
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)
- Dans la section, Droplets, puis le dossier du site en question
- Ensuite dans Console
- Vous devriez voir une console en linux pour faire les modifications
- Naviguer à travers les fichiers pour trouver le dossier recherché
- 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 installsur 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 fixpourrait être intéressant pour fix les soucis de package conflict. [Autre Solution Non recommandé] Pour être aussinpm audit fix --force, cependant ceci risque de brisser des packages.
- Note 2.1: Un
- 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.
- Faire la commande suivante si c'est le cas (forge fait référence au username, changer selon le cas)
-
su - forge
-
- Faire la commande suivante si c'est le cas (forge fait référence au username, changer selon le cas)
- Utiliser les commandes nécessaire à vos changements
- Remettre à l'état d'origine le dossier
-
git reset .
-
git reset --hard
-
git reset --hardrisque de nécessiterorigin/mastercomme 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
-
- Remettre à l'état d'origine le dossier
- Faire
cd uniksim-back-end, puis fairenpm run buildpour appliquer les changements - (optionnel) Faire
npm run startpour 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 :
- Pour les build, utiliser la commande Build Frontend project
- Si cela n'est pas possible, utiliser la commande ci-dessous dans un terminal (dans le dossier uniksimFrontEnd)
ng build
- Vous devriez avoir créer un build nommer Front dans le dossier uniksim-back-end
- 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/**/*"} - Note: si vous changez unity build (ex: Build.data.unityweb), s'assurer de mettre la même version dans constantsVariable
Notes :
- 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:
https://stackoverflow.com/questions/3958615/import-file-size-limit-in-phpmyadmin
- La commande pour envoyer le serveur backend en local (il faut bien sûr "cd" dans le bon dossier) :
npm run start
- Version en live/demo :
npm run start:live
- Cette commande nécessite le build
npm run build
- Cette commande nécessite le build
- Version en live/demo :
-
- Celui du frontend est :
ng serve
- Celui du frontend est :
- 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&db=uniksim&table=constants&pos=0
- La commande pour lancer admin_server (après su- forge) :
node sim.dev.uniksim.com/uniksim-back-end/src/node.js/server/admin_server.js
- Il est possible d'ajouter un paramètre :
node admin_server.js dev
- Il est possible d'ajouter un paramètre :
Problèmes :
- 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
- Faite
sudo lsof -i :3000pour trouver le node en cours -
~hFHs>!SLx3)d4Yc_HbQsi nécessaire - Puis
kill -9 <PID>pour le terminer - Refaire votre commande
- Faite
Les références de création :
- Site de NestJs : https://docs.nestjs.com/first-steps
- Site de compatibilité de version Angular/Node : 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
- Configuration de NestJs/MySQL (phpMyAdmin) : https://blog.stackademic.com/connecting-nestjs-to-mysql-a-step-by-step-guide-ab4086baf918
- Configuration de NestJs : 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
- Decoration pour les expressions Sql : https://typeorm.io/decorator-reference#column-decorators
- Typeorm wiki (NestJs/Sql data communication) : https://orkhan.gitbook.io/typeorm/docs/find-options
- Debugger for NestJs : 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
- TypeOrm relations (Many-to-one / one-to-many): 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
- Build le projet Angular à l'intérieur de Nestjs : 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
- Erreur commun pour nvm lorsqu'il refuse de changer de version : 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
1) Se déplacer au bon dossier :
-
- Avec la command suivante
cd {uniksim}/frontend/angular
2) Build Angular :
-
- Avec la command suivante
ng build
3) Modifier le angular.blade.php :
Situé à {uniksim}/resources/views/angular.blade.php
-
- Remplacer les balises html, head et base
- Remplacer les balises html, head et base
|
@extends('layouts.app') @section('title') @section('applink') @stop @section('content') |
-
- Remplacer les balises body et html
- Remplacer les balises body et html
|
@endsection |
-
- 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 frontEnd et backEnd (source)
- localhost:3000 utilise uniquement le backEnd (source) et la version build du frontEnd
De plus, ce tutoriel va modifier la connexion à titre d'exemple
- Activer le site sous Launch Frontend and Backend (dev)
- Vérifier que tout soit en marche :
- Sur le frontEnd vous devriez avoir
- Sur le backend vous devriez avoir (les messages peuvent varier d'ordre)
- Sur le frontEnd vous devriez avoir
-
Ouvrir une session localhost:4200 web - Sous Sources>Page>webpack://>login>login.component.ts
- Mettre des points d'arrêts sur la requête attendu
- Envoyer la requête, vous devriez commencé à débugger
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
*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
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 |
|
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
*note: Un test de ressources et de simulation démo seront vu ci-dessous. Ajouter un produit enseignant à cet étape serait pratique pour vous |
|
Jouer à la simulation :Vérifier que les produits fonctionnent bien en cliquant dessus. Ceci inclus:
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 |
|
La liste des produits :Vérifier que tous les produits sont bien présents. Faites particulièrement attention à l'ajout de Démo |
|
L'affichage des ressources :Vérifier que le bouton Ressources fonctionne et que ses liens fonctionnent aussi
Vérifier également les options offertes :
|
|
Les liens externes :Vérifier que tous les liens en bas de page se dirigent bien sur les informations pertinentes |
|
Bouton d'accueil :Vérifier que le bouton Uniksim essaie, joue, apprends se dirige vers l'accueil des produits |
|
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 |
|
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 |
|
SignOff :Vérifier que le bouton Se déconnecter se dirige bien vers la page d'accueil
Ceci devrait supprimer le token (dans LocalStorage) |
|
Page Mot de passe oublié :Vérifier que le changement de mot de passe fonctionne bien
*note: Un email valide sera requis |
|
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
Ceci devrait créer un token (dans LocalStorage) |
|
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 |
|
Les boutons de retour :Vérifier que tous les boutons de retour de la page d'accueil fonctionnent bel et bien |
|
Les cookies :Vérifier que les cookies (provenant de cookieYes) fonctionnent bel et bien |
|
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 |
|
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 |
|
La page admin :Vérifier que seulement une partie de la page admin est affichée. Ceci inclus:
|
|
La page admin (filtre) :Vérifier que tous les filtres fonctionnes |
|
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 |
|
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 |
|
La désactivation de produit :Vérifier que la suppression de produit sous
Ceci devrait uniquement rendre le produit non actif |
|
La page admin :Vérifier que tous les options sont disponible. Cela inlus :
|
|
La page user :Vérifier que tous les informations sont présentés. Cela peut inclure :
Vérifier aussi les cas d'échecs (si possible)
*note: Il est nécessaire de tester ce cas sur plusieurs utilisateurs différents, car ils ont chacun des cas distincts
Requis: Brainlcloud |
|
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)
Requis: Brainlcloud |
|
La page user (Options) :Vérifier que le copySim fonctionne bien sur différents cas
Vérifier aussi les cas d'échecs (si possible)
Requis: Brainlcloud |
|
Jouer à la simulation :Vérifier que les simulations sont disponibles pour être lancées sur différentes Braincloud. Ceci inclus :
*note: Il n'est pas nécessaire d'approfondir l'utilisation du jeu. Juste pouvoir l'ouvrir est suffisant. |
|
La page commentaire :Vérifier que le filtre et les informations sont disponibles
Vérifier aussi les cas d'échecs (si possible)
Requis: Brainlcloud |
|
La page actives :Vérifier que le filtre et les informations sont disponibles
Vérifier aussi les cas d'échecs (si possible)
Requis: Brainlcloud |
|
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.
|
|
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 |
|
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 |
|
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 |
|
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 |
|
Compte test - Création de compte
Liste de tous les comptes créé pour tester la création de compte
|
|
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 |
Local database (PHPMyAdmin) - Conflict
Local database (PHPMyAdmin) - Conflict
- Si vous avez une erreur comme ci-dessous avec XAMPP, suivez les fixs de cette vidéo : https://www.youtube.com/watch?v=OEUVth2Av48 (Généralement, le dossier backup fix l'erreur "0:41")
- Si vous avez cette erreur en utilisant XAMPP :
- Faire une suppression de toute Cookies et de LocalStorage
- Si vous ne trouvez pas l'option drop database
- Suivre les méthode de ce lien : 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>Config)
- En bref: Ajouter
- Suivre les méthode de ce lien : https://stackoverflow.com/questions/4410630/phpmyadmin-enable-drop-database-statement
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:
- Avec les touches
CTRL + SHIFT + B, vous devez avoir les paramètres suivants sur Unity - Regarder la version de votre Unity dans le fichier
version.txt(situé à "Assets/Ressources/data/version.txt"). -
Changer la version du build dans la version locale du backend en web (Dans le fichier
constantsVariable.js).- Changer :
LOCAL_WEBGL_VERSION: {votre version}
- Changer :
-
Changer la version du build dans la version locale du database (Situé dans constants)
- Une fois le build de Unity terminé, mettre les fichiers du build dans le frontend (Dans le dossier
uniksimFrontEnd\src\assets\unity\Build)- 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.
- Faire un build du frontend
- Tester 🥳
Erreurs courantes:
- Si vous avez :
-
Une des versions de votre build (en backend ou en database) ne correspond pas. Veuillez revoir les étapes 3 et 4.
-