Skip to content

Vue d'ensemble de l'architecture

Notre architecture est composée de trois couches principales :

Vue d'ensemble
100%
architecture-beta
    group architecture(cloud)[Architecture]

    service client(internet)[Frontend] in architecture
    service api(server)[API] in architecture
    service ia(server)[IA] in architecture
    service db(database)[Donnees] in architecture

    client:R -- L:api
    api:R -- L:db
    api:B -- T:ia

Données

PostgreSQL + S3 - Stockage relationnel et objets

Notre infrastructure est déployée sur des services cloud européens pour garantir la conformité RGPD :

Architecture Cloud
100%
flowchart LR
 subgraph Client["Client"]
        RN["React Native"]
  end
 subgraph DNS["DNS"]
        API_DNS["api.mindlet.app"]
        WS_DNS["ws.mindlet.app"]
  end
 subgraph Ingress["Nginx Ingress Controller"]
        LB["Load Balancer"]
        RT["Router"]
  end
 subgraph API["API Deployment"]
        OCT["Laravel Octane"]
        POD_API1["POD"]
        POD_API2["POD"]
        POD_API3["POD"]
  end
 subgraph WS["WS Deployment"]
        REV["Laravel Reverb"]
        POD_WS["POD"]
  end
 subgraph REDIS["Redis Service"]
        REDIS_APP["Redis"]
        POD_REDIS["POD"]
  end
 subgraph WORKERS["Worker supervisors"]
        HZ["Laravel Horizon"]
        POD_W1["POD"]
        POD_W2["POD"]
        POD_W3["POD"]
  end
 subgraph K8S["OVH Cloud Kubernetes Cluster"]
        Ingress
        API_SVC(("api-service"))
        WS_SVC(("ws-service"))
        API
        WS
        REDIS
        WORKERS
  end
 subgraph Neon["Neon"]
        PG[("PostgreSQL")]
  end
 subgraph Qdrant["Qdrant Cloud"]
        VDB[("Vector DB")]
  end
 subgraph LangGraph["LangGraph Cloud"]
        CARD["Card generation"]
        EMB["Embeddings"]
  end
    RN --> API_DNS & WS_DNS
    LB --> RT
    API_DNS --> LB
    WS_DNS --> LB
    RT --> API_SVC & WS_SVC
    OCT --> POD_API1 & POD_API2 & POD_API3
    REV --> POD_WS
    REDIS_APP --> POD_REDIS
    HZ --> POD_W1 & POD_W2 & POD_W3
    API_SVC --> API
    WS_SVC --> WS
    API <--> REDIS
    WS <--> REDIS
    WORKERS <--> REDIS
    API --> PG & VDB & CARD & EMB
ComposantServiceFournisseur
OrchestrationKubernetesOVHcloud
Load BalancerCloud Load BalancerOVHcloud
Base de donnéesPostgreSQL ManagedNeon
Base vectorielleQdrant ManagedQdrant Cloud
Stockage objetsVPSHetzner

La couche prĂ©sentation est responsable de l’interface utilisateur :

  • Technologie : React Native avec Expo
  • État global : Zustand
  • Navigation : Expo Router
  • UI Components : NativeWind (Tailwind CSS)
  • RequĂȘtes API : React Query

Cette couche ne contient aucune logique métier et se contente de :

  • Afficher les donnĂ©es reçues de l’API
  • Capturer les interactions utilisateur
  • Envoyer les requĂȘtes au backend
Frontend to Backend
100%
flowchart LR
    subgraph Frontend
        MOB[React Native]
    end
    subgraph Backend
        API[Laravel]
    end
    subgraph Service IA
        IA[LangGraph]
    end
    MOB <-->|REST API JSON| API
    API <-->|REST API JSON| IA

Caractéristiques :

  • Communication via HTTPS exclusivement
  • Format d’échange : JSON
  • Authentification : JWT (Bearer Token)

Notre architecture est conçue pour supporter une montée en charge :

  • Kubernetes HPA : Auto-scaling des pods selon la charge CPU/mĂ©moire
  • Load Balancer : Distribution de charge entre les instances
  • Stateless API : Chaque instance peut traiter n’importe quelle requĂȘte
  • Workers dĂ©diĂ©s : Pods spĂ©cialisĂ©s pour les traitements IA lourds
  • Queues : Gestion asynchrone des tĂąches longues
  • Base de donnĂ©es managed : Scaling automatique par le provider
UtilisateursInstances APIInstances IADB Connections
1001210
5 0002450
50 000+4+8+200+

La base de donnĂ©es de Mindlet suit une modĂ©lisation rigoureuse qui distingue le niveau conceptuel (abstrait, indĂ©pendant de l’implĂ©mentation) du niveau physique (concret, spĂ©cifique Ă  PostgreSQL).

Le MCD reprĂ©sente les entitĂ©s mĂ©tier et leurs associations de maniĂšre abstraite, sans se soucier des dĂ©tails techniques d’implĂ©mentation.

Caractéristiques :

  • ReprĂ©sente le “quoi” : quelles donnĂ©es et quelles relations
  • IndĂ©pendant du SGBD (PostgreSQL, MySQL, etc.)
  • Utilise des concepts de haut niveau (entitĂ©s, associations, cardinalitĂ©s)
  • Sert de base de discussion avec les parties prenantes non-techniques

Notation utilisée :

  • EntitĂ© : Rectangle (ex: USERS, CARDS)
  • Attribut : PropriĂ©tĂ© d’une entitĂ© (ex: name, email)
  • Association : Ligne reliant deux entitĂ©s avec cardinalitĂ©s

Cardinalités :

  • ||--o{ : Un Ă  plusieurs (1,N)
  • ||--|| : Un Ă  un (1,1)
  • }o--o{ : Plusieurs Ă  plusieurs (N,M)

Le schéma de données de Mindlet comprend 35+ tables organisées en domaines fonctionnels :

DomaineTables principalesDescription
Utilisateursusers, user_follows, user_friendships, user_achievementsGestion des comptes, relations sociales et gamification
Collectionscollections, collection_collaborators, tags, taggablesOrganisation hiérarchique du contenu avec collaboration
Cartescards, card_progressionsCartes d’apprentissage (9 types) et suivi de progression
Étudestudy_sessionsSessions de rĂ©vision avec mĂ©triques
IAai_resource_batches, ai_resource_items, ai_resource_embeddings, ai_card_generations, user_ai_quotasPipeline de génération IA et gestion des quotas
Messagerieconversations, messages, groups, conversation_participantsSystÚme de messagerie temps réel
Socialposts, post_reactions, post_mentionsFil d’actualitĂ© et interactions
Organisationsorganizations, organization_members, organization_invitationsGestion des établissements
Authpersonal_access_tokens, social_accounts, roles, permissionsAuthentification et autorisations

Le diagramme ci-dessous présente les entités principales et leurs relations :

MCD
100%
erDiagram
	direction TB
	USERS {
		uuid id PK ""
		string name  ""
		string email  ""
		timestamp email_verified_at  ""
		string password  ""
		string remember_token  ""
		timestamp created_at  ""
		timestamp updated_at  ""
	}

	ORGANIZATIONS {
		uuid id PK ""
		string name  ""
		string slug  ""
		string description  ""
		timestamp created_at  ""
		timestamp updated_at  ""
	}

	ORGANIZATION_MEMBERS {
		uuid id PK ""
		uuid organization_id FK ""
		uuid user_id FK ""
		string role  ""
		timestamp created_at  ""
		timestamp updated_at  ""
	}

	ORGANIZATION_INVITATIONS {
		uuid id PK ""
		uuid organization_id FK ""
		uuid inviter_id FK ""
		string invitee_email  ""
		string token  ""
		timestamp expires_at  ""
		timestamp created_at  ""
		timestamp updated_at  ""
	}

	COLLECTIONS {
		uuid id PK ""
		uuid owner_id FK ""
		uuid parent_id FK ""
		uuid organization_id FK ""
		string title  ""
		string description  ""
		timestamp created_at  ""
		timestamp updated_at  ""
	}

	COLLECTION_COLLABORATORS {
		uuid id PK ""
		uuid collection_id FK ""
		uuid user_id FK ""
		string role  ""
		timestamp created_at  ""
		timestamp updated_at  ""
	}

	CARDS {
		uuid id PK ""
		uuid collection_id FK ""
		string type  ""
		string front  ""
		string back  ""
		timestamp created_at  ""
		timestamp updated_at  ""
	}

	CARD_PROGRESSIONS {
		uuid id PK ""
		uuid user_id FK ""
		uuid card_id FK ""
		timestamp last_reviewed_at  ""
		integer streak  ""
		timestamp created_at  ""
		timestamp updated_at  ""
	}

	STUDY_SESSIONS {
		uuid id PK ""
		uuid user_id FK ""
		uuid collection_id FK ""
		string status  ""
		timestamp started_at  ""
		timestamp ended_at  ""
		timestamp created_at  ""
		timestamp updated_at  ""
	}

	TAGS {
		uuid id PK ""
		string name  ""
		string color  ""
		timestamp created_at  ""
		timestamp updated_at  ""
	}

	TAGGABLES {
		bigint id PK ""
		uuid tag_id FK ""
		uuid taggable_id  ""
		string taggable_type  ""
		timestamp created_at  ""
		timestamp updated_at  ""
	}

	USER_ACHIEVEMENTS {
		uuid id PK ""
		uuid user_id FK ""
		string achievement_key  ""
		timestamp unlocked_at  ""
		timestamp created_at  ""
		timestamp updated_at  ""
	}

	USER_FOLLOWS {
		uuid id PK ""
		uuid follower_id FK ""
		uuid followed_id FK ""
		timestamp created_at  ""
	}

	USER_FRIENDSHIPS {
		uuid id PK ""
		uuid requester_id FK ""
		uuid addressee_id FK ""
		string status  ""
		timestamp created_at  ""
		timestamp updated_at  ""
	}

	POSTS {
		uuid id PK ""
		uuid author_id FK ""
		uuid collection_id FK ""
		string content  ""
		timestamp published_at  ""
		timestamp created_at  ""
		timestamp updated_at  ""
	}

	POST_MENTIONS {
		uuid id PK ""
		uuid post_id FK ""
		uuid mentionable_id  ""
		string mentionable_type  ""
		timestamp created_at  ""
		timestamp updated_at  ""
	}

	POST_REACTIONS {
		uuid id PK ""
		uuid post_id FK ""
		uuid user_id FK ""
		string kind  ""
		timestamp created_at  ""
		timestamp updated_at  ""
	}

	CONVERSATIONS {
		uuid id PK ""
		string type  ""
		string topic  ""
		timestamp created_at  ""
		timestamp updated_at  ""
	}

	DIRECT_CONVERSATIONS {
		uuid id PK ""
		uuid conversation_id FK ""
		uuid user_one_id FK ""
		uuid user_two_id FK ""
		timestamp created_at  ""
		timestamp updated_at  ""
	}

	GROUPS {
		uuid id PK ""
		uuid conversation_id FK ""
		uuid owner_id FK ""
		string name  ""
		string description  ""
		timestamp created_at  ""
		timestamp updated_at  ""
	}

	CONVERSATION_PARTICIPANTS {
		uuid id PK ""
		uuid conversation_id FK ""
		uuid user_id FK ""
		timestamp joined_at  ""
		timestamp created_at  ""
		timestamp updated_at  ""
	}

	MESSAGES {
		uuid id PK ""
		uuid conversation_id FK ""
		uuid sender_id FK ""
		string content  ""
		timestamp sent_at  ""
		timestamp created_at  ""
		timestamp updated_at  ""
	}

	MESSAGE_REACTIONS {
		uuid id PK ""
		uuid message_id FK ""
		uuid user_id FK ""
		string kind  ""
		timestamp created_at  ""
		timestamp updated_at  ""
	}

	GROUP_INVITATIONS {
		uuid id PK ""
		uuid group_id FK ""
		uuid inviter_id FK ""
		uuid invitee_id FK ""
		string status  ""
		timestamp created_at  ""
		timestamp updated_at  ""
	}

	AI_RESOURCE_BATCHES {
		uuid id PK ""
		uuid user_id FK ""
		string status  ""
		timestamp created_at  ""
		timestamp updated_at  ""
	}

	AI_RESOURCE_ITEMS {
		uuid id PK ""
		uuid batch_id FK ""
		string resource_type  ""
		string file_hash  ""
		timestamp created_at  ""
		timestamp updated_at  ""
	}

	AI_RESOURCE_EMBEDDINGS {
		uuid id PK ""
		uuid item_id FK ""
		string embedding_type  ""
		timestamp created_at  ""
		timestamp updated_at  ""
	}

	AI_CARD_GENERATIONS {
		uuid id PK ""
		uuid user_id FK ""
		string generation_key  ""
		timestamp created_at  ""
		timestamp updated_at  ""
	}

	USER_AI_QUOTAS {
		uuid id PK ""
		uuid user_id FK ""
		integer monthly_quota  ""
		integer used  ""
		timestamp reset_at  ""
		timestamp created_at  ""
		timestamp updated_at  ""
	}

	MEDIA {
		bigint id PK ""
		uuid model_id  ""
		string model_type  ""
		string file_name  ""
		string disk  ""
		string path  ""
		timestamp created_at  ""
		timestamp updated_at  ""
	}

	SOCIAL_ACCOUNTS {
		uuid id PK ""
		uuid user_id FK ""
		string provider  ""
		string provider_user_id  ""
		timestamp created_at  ""
		timestamp updated_at  ""
	}

	PERSONAL_ACCESS_TOKENS {
		bigint id PK ""
		uuid tokenable_id  ""
		string tokenable_type  ""
		string name  ""
		string token  ""
		timestamp last_used_at  ""
		timestamp created_at  ""
		timestamp updated_at  ""
	}

	PERMISSIONS {
		bigint id PK ""
		string name  ""
		string guard_name  ""
		timestamp created_at  ""
		timestamp updated_at  ""
	}

	ROLES {
		bigint id PK ""
		string name  ""
		string guard_name  ""
		timestamp created_at  ""
		timestamp updated_at  ""
	}

	MODEL_HAS_PERMISSIONS {
		bigint permission_id FK ""
		uuid model_id  ""
		string model_type  ""
	}

	MODEL_HAS_ROLES {
		bigint role_id FK ""
		uuid model_id  ""
		string model_type  ""
	}

	ROLE_HAS_PERMISSIONS {
		bigint permission_id FK ""
		bigint role_id FK ""
	}

	USERS||--o{COLLECTIONS:"owns"
	COLLECTIONS|o--o{ORGANIZATIONS:"assigned_to"
	USERS||--o{COLLECTION_COLLABORATORS:"collaborates"
	COLLECTIONS||--o{COLLECTION_COLLABORATORS:"has_collaborator"
	COLLECTIONS||--o{CARDS:"contains"
	USERS||--o{CARD_PROGRESSIONS:"tracks"
	CARDS||--o{CARD_PROGRESSIONS:"progress"
	USERS||--o{STUDY_SESSIONS:"runs"
	COLLECTIONS||--o{STUDY_SESSIONS:"studied_in"
	TAGS||--o{TAGGABLES:"links"
	COLLECTIONS|o--o{TAGGABLES:"tagged_collection"
	CARDS|o--o{TAGGABLES:"tagged_card"
	USERS||--o{USER_ACHIEVEMENTS:"earns"
	USERS||--o{USER_FOLLOWS:"follower"
	USER_FOLLOWS}o--||USERS:"followed"
	USERS||--o{USER_FRIENDSHIPS:"requests"
	USER_FRIENDSHIPS}o--||USERS:"friend"
	USERS||--o{POSTS:"authors"
	COLLECTIONS|o--o{POSTS:"feeds"
	POSTS||--o{POST_REACTIONS:"receives_reaction"
	USERS||--o{POST_REACTIONS:"reacts"
	POSTS||--o{POST_MENTIONS:"mentions"
	POST_MENTIONS}o--||USERS:"mention_target"
	CONVERSATIONS||--o{MESSAGES:"contains"
	USERS||--o{MESSAGES:"sends"
	CONVERSATIONS||--o{CONVERSATION_PARTICIPANTS:"has_participant"
	USERS||--o{CONVERSATION_PARTICIPANTS:"participates"
	CONVERSATIONS||--||DIRECT_CONVERSATIONS:"direct_thread"
	DIRECT_CONVERSATIONS||--o{USERS:"user_one"
	DIRECT_CONVERSATIONS||--o{USERS:"user_two"
	CONVERSATIONS||--||GROUPS:"group_thread"
	GROUPS||--o{GROUP_INVITATIONS:"issues"
	USERS||--o{GROUP_INVITATIONS:"invites"
	GROUP_INVITATIONS}o--||USERS:"invited"
	GROUPS||--o{CONVERSATION_PARTICIPANTS:"members"
	MESSAGES||--o{MESSAGE_REACTIONS:"receives_reaction"
	USERS||--o{MESSAGE_REACTIONS:"reacts"
	USERS||--o{AI_RESOURCE_BATCHES:"submits_batch"
	AI_RESOURCE_BATCHES||--o{AI_RESOURCE_ITEMS:"includes_item"
	AI_RESOURCE_ITEMS||--o{AI_RESOURCE_EMBEDDINGS:"has_embedding"
	USERS||--o{AI_CARD_GENERATIONS:"requests_generation"
	USERS||--o{USER_AI_QUOTAS:"quota_records"
	AI_RESOURCE_ITEMS}o--||MEDIA:"stored_media"
	USERS||--o{SOCIAL_ACCOUNTS:"links_account"
	USERS||--o{PERSONAL_ACCESS_TOKENS:"tokens"
	PERMISSIONS||--o{ROLE_HAS_PERMISSIONS:"granted_to_role"
	ROLES||--o{ROLE_HAS_PERMISSIONS:"aggregates_permission"
	ROLES||--o{MODEL_HAS_ROLES:"assigned_to"
	USERS||--o{MODEL_HAS_ROLES:"user_role"
	PERMISSIONS||--o{MODEL_HAS_PERMISSIONS:"assigned_to"
	USERS||--o{MODEL_HAS_PERMISSIONS:"user_permission"
	ORGANIZATIONS||--o{ORGANIZATION_MEMBERS:"has_member"
	USERS||--o{ORGANIZATION_MEMBERS:"membership"
	ORGANIZATIONS||--o{ORGANIZATION_INVITATIONS:"issues_invite"
	USERS||--o{ORGANIZATION_INVITATIONS:"invites"

Le MPD ci-dessous montre l’implĂ©mentation PostgreSQL avec les types de donnĂ©es, contraintes et index :

MPD

Types utilisés dans le schéma :

TypeUsageExemple
uuidClés primaires et étrangÚresid, user_id, collection_id
jsonbDonnées flexibles indexablescards.data, cards.config
timestamptzHorodatages avec timezonecreated_at, updated_at
textChaĂźnes de longueur variabletitle, description, content
varchar(n)Chaßnes limitéesemail, type, status
booleanValeurs binairesis_unlimited, exclude_from_embedding
integerCompteurs et quotasdaily_generations_used
RelationTypeDescription
User → Collections1:NUn utilisateur possùde plusieurs collections
Collection → Cards1:NUne collection contient plusieurs cartes
User ↔ CollectionsN:MCollaboration via collection_collaborators
Card → CardProgressions1:NProgression par utilisateur et par carte
User → AiCardGenerations1:NHistorique des gĂ©nĂ©rations IA
AiResourceBatch → Items → Embeddings1:N:NPipeline d’ingestion des ressources

Architecture conçue pour la performance, la scalabilité et la maintenabilité.