chore: initial commit
This commit is contained in:
commit
03f03f7ad2
39 files changed
+7292
No files matched your search
@@ -0,0 +1,70 @@
|
||||
@startuml c4-container
|
||||
' C4 modèle — Niveau 2 : Conteneurs (syntaxe native PlantUML, compatible anciennes versions)
|
||||
' Application web Flashcards (SPA/PWA)
|
||||
|
||||
hide stereotype
|
||||
skinparam backgroundColor #FFFFFF
|
||||
|
||||
' ===== Styles par type =====
|
||||
skinparam rectangle<<person>> {
|
||||
BackgroundColor #08427B
|
||||
BorderColor #073B6F
|
||||
FontColor #FFFFFF
|
||||
}
|
||||
|
||||
skinparam rectangle<<system>> {
|
||||
'BackgroundColor #1168BD
|
||||
BorderColor #3C7FC0
|
||||
FontColor #FFFFFF
|
||||
}
|
||||
|
||||
skinparam rectangle<<container>> {
|
||||
BackgroundColor #438DD5
|
||||
BorderColor #135F97
|
||||
FontColor #FFFFFF
|
||||
}
|
||||
|
||||
skinparam rectangle<<external_system>> {
|
||||
BackgroundColor #999999
|
||||
BorderColor #8A8A8A
|
||||
FontColor #FFFFFF
|
||||
}
|
||||
|
||||
skinparam arrow {
|
||||
Color #707070
|
||||
}
|
||||
|
||||
title Conteneurs — Flashcards (Niveau 2)
|
||||
|
||||
' ===== Personne =====
|
||||
rectangle "Utilisateur\nNavigateur / mobile\n(accès au jeu et au CRUD)" <<person>> as User
|
||||
|
||||
' ===== Système Flashcards et ses conteneurs =====
|
||||
rectangle "Application Flashcards [Système]\nSPA/PWA Next.js — double persistance simultanée" <<system>> as Flashcards {
|
||||
|
||||
rectangle "SPA React (Next.js)\n[Conteneur : Web Browser]\nRendu de l'UI, état local, navigation" <<container>> as Spa
|
||||
|
||||
rectangle "API Next.js / App Router\n[Conteneur : Node.js]\nCardController > CardService :\nliste, CRUD, tirage aléatoire, thèmes\n(seul conteneur qui accède aux données)" <<container>> as Api
|
||||
|
||||
rectangle "CardRepository (générique)\n[Abstraction de données]\nContracts : findAll, findById,\nfindRandom, findRandomByTheme,\nfindThemes, create, update, delete" <<container>> as Repo
|
||||
|
||||
rectangle "Implémentation MySQL\n[Conteneur : librairie]\nImplémentation SQL du repository" <<container>> as RepoMysql
|
||||
rectangle "Implémentation MongoDB\n[Conteneur : librairie]\nImplémentation Mongo du repository" <<container>> as RepoMongo
|
||||
}
|
||||
|
||||
' ===== Systèmes externes =====
|
||||
rectangle "Base MySQL\n[Conteneur externe : SGBD]\nPersistance des cartes (table cards)\n+ stockage Docker avec volume" <<external_system>> as MySql
|
||||
rectangle "Base MongoDB\n[Conteneur externe : SGBD]\nPersistance des cartes (collection cards)\n+ stockage Docker avec volume" <<external_system>> as Mongo
|
||||
'rectangle "Docker / docker-compose\n[infrastructure]\nOrchestration des conteneurs\nweb + bases + volumes" <<external_system>> as Docker
|
||||
|
||||
' ===== Relations =====
|
||||
User -[#707070]-> Spa : "Navigue et interagit (HTTP/HTTPS)"
|
||||
Spa -[#707070]-> Api : "Appels API JSON (dialogues, CRUD,\ntirage, révélation de réponse)"
|
||||
Api -[#707070]down-> Repo : "Utilise uniquement l'abstraction"
|
||||
Repo -[#707070]-> RepoMysql : "implémente"
|
||||
Repo -[#707070]-> RepoMongo : "implémente"
|
||||
Api -[#707070]down-> MySql : "Tables SQL via repository\n(selectionné par config/driver)"
|
||||
Api -[#707070]down-> Mongo : "Requêtes Mongo via repository\n(selectionné par config/driver)"
|
||||
'Docker -[#707070]-> MySql : "Démarre / arrête (docker-compose)"
|
||||
'Docker -[#707070]-> Mongo : "Démarre / arrête (docker-compose)"
|
||||
@enduml
|
||||
@@ -0,0 +1,55 @@
|
||||
@startuml c4-context
|
||||
' C4 modèle — Niveau 1 : Contexte système (syntaxe native PlantUML, compatible anciennes versions)
|
||||
' Application web Flashcards (SPA/PWA)
|
||||
|
||||
hide stereotype
|
||||
skinparam backgroundColor #FFFFFF
|
||||
|
||||
' ===== Styles par type =====
|
||||
skinparam rectangle<<person>> {
|
||||
BackgroundColor #08427B
|
||||
BorderColor #073B6F
|
||||
FontColor #FFFFFF
|
||||
}
|
||||
|
||||
skinparam rectangle<<external_person>> {
|
||||
BackgroundColor #686868
|
||||
BorderColor #8A8A8A
|
||||
FontColor #FFFFFF
|
||||
}
|
||||
|
||||
skinparam rectangle<<system>> {
|
||||
BackgroundColor #1168BD
|
||||
BorderColor #3C7FC0
|
||||
FontColor #FFFFFF
|
||||
}
|
||||
|
||||
skinparam rectangle<<external_system>> {
|
||||
BackgroundColor #999999
|
||||
BorderColor #8A8A8A
|
||||
FontColor #FFFFFF
|
||||
}
|
||||
|
||||
skinparam arrow {
|
||||
Color #707070
|
||||
}
|
||||
|
||||
title Contexte système — Flashcards (Niveau 1)
|
||||
|
||||
' ===== Personnes =====
|
||||
rectangle "Utilisateur\nJoueur et contributeur de cartes\n(CRUD) : code, dev, culture tech" <<person>> as User
|
||||
|
||||
' ===== Système à modéliser =====
|
||||
rectangle "App Flashcards\nSPA/PWA Next.js — tirage de cartes au\nhasard, tirage par thème, CRUD des cartes.\nDouble persistance simultanée\nMySQL + MongoDB via couche générique." <<system>> as Flashcards
|
||||
|
||||
' ===== Systèmes externes =====
|
||||
rectangle "MySQL\nBase relationnelle\n(conteneur Docker)" <<external_system>> as MySql
|
||||
rectangle "MongoDB\nBase documentaire\n(conteneur Docker)" <<external_system>> as Mongo
|
||||
'rectangle "Docker / docker-compose\nOrchestration des conteneurs\n(web, bases) + volumes persistants" <<external_system>> as Docker
|
||||
|
||||
User -[#707070]-> Flashcards : Joue, crée, modifie, supprime,\nconsulte et révèle des cartes
|
||||
Flashcards -[#707070]-> MySql : Lit / écrit (CardRepository)
|
||||
Flashcards -[#707070]-> Mongo : Lit / écrit (CardRepository)
|
||||
'Docker -[#707070]-> MySql : Démarre et gère
|
||||
'Docker -[#707070]-> Mongo : Démarre et gère
|
||||
@enduml
|
||||
@@ -0,0 +1,105 @@
|
||||
@startuml
|
||||
' Diagramme de classes — Application web Flashcards (Architecture : couche d'accès générique)
|
||||
skinparam classAttributeIconSize 0
|
||||
skinparam classFontStyle bold
|
||||
|
||||
' ===== Domaine =====
|
||||
class Card {
|
||||
- id : string
|
||||
- question : string
|
||||
- response : string
|
||||
- theme : string
|
||||
- tags : string[]
|
||||
- createdAt : Date
|
||||
- updatedAt : Date
|
||||
+ Card(id, question, response, theme, tags)
|
||||
+ validate() : void
|
||||
}
|
||||
|
||||
' ===== Abstraction générique d'accès aux données =====
|
||||
interface CardRepository {
|
||||
+ findAll() : Promise<Card[]>
|
||||
+ findById(id : string) : Promise<Card | null>
|
||||
+ findRandom() : Promise<Card | null>
|
||||
+ findRandomByTheme(theme : string) : Promise<Card | null>
|
||||
+ findThemes() : Promise<string[]>
|
||||
+ create(card : Card) : Promise<Card>
|
||||
+ update(card : Card) : Promise<Card>
|
||||
+ delete(id : string) : Promise<boolean>
|
||||
}
|
||||
|
||||
' ===== Implémentations SGBD =====
|
||||
class MysqlCardRepository {
|
||||
- connection : MysqlConnection
|
||||
+ MysqlCardRepository(connection)
|
||||
}
|
||||
|
||||
class MongoCardRepository {
|
||||
- collection : MongoCollection
|
||||
+ MongoCardRepository(collection)
|
||||
}
|
||||
|
||||
class "MysqlConnection" as ConnMysql {
|
||||
- host : string
|
||||
- port : number
|
||||
- user : string
|
||||
- password : string
|
||||
- database : string
|
||||
+ query(sql : string, params : unknown[]) : Promise<unknown>
|
||||
}
|
||||
|
||||
class "MongoCollection" as ColMongo {
|
||||
+ find(filter : object) : Promise<unknown[]>
|
||||
+ insertOne(doc : object) : Promise<unknown>
|
||||
+ updateOne(filter : object, update : object) : Promise<unknown>
|
||||
+ deleteOne(filter : object) : Promise<unknown>
|
||||
}
|
||||
|
||||
class DatabaseConfig {
|
||||
- driver : string
|
||||
+ getActiveDriver() : string
|
||||
}
|
||||
|
||||
' ===== Service métier (dépend uniquement de l'abstraction) =====
|
||||
class CardService {
|
||||
- repository : CardRepository
|
||||
+ CardService(repository : CardRepository)
|
||||
+ listCards() : Promise<Card[]>
|
||||
+ getCard(id : string) : Promise<Card>
|
||||
+ createCard(payload : NewCardPayload) : Promise<Card>
|
||||
+ updateCard(id : string, payload : UpdateCardPayload) : Promise<Card>
|
||||
+ deleteCard(id : string) : Promise<void>
|
||||
+ playRandom(theme? : string) : Promise<Card>
|
||||
+ listThemes() : Promise<string[]>
|
||||
}
|
||||
|
||||
' ===== Couche exposition (routes / contrôleur) =====
|
||||
class CardController {
|
||||
+ handleList(req, res) : Promise<void>
|
||||
+ handleGetById(req, res) : Promise<void>
|
||||
+ handleCreate(req, res) : Promise<void>
|
||||
+ handleUpdate(req, res) : Promise<void>
|
||||
+ handleDelete(req, res) : Promise<void>
|
||||
+ handlePlayRandom(req, res) : Promise<void>
|
||||
+ handleThemes(req, res) : Promise<void>
|
||||
}
|
||||
|
||||
class Factory {
|
||||
{static} buildCardRepository(config : DatabaseConfig) : CardRepository
|
||||
}
|
||||
|
||||
' ===== Relations =====
|
||||
CardRepository <|.. MysqlCardRepository
|
||||
CardRepository <|.. MongoCardRepository
|
||||
|
||||
MysqlCardRepository *-- ConnMysql : utilise >
|
||||
MongoCardRepository *-- ColMongo : utilise >
|
||||
|
||||
CardService *-- CardRepository : <<injecté>> utilise >
|
||||
CardService ..> Card : < crée/retourne
|
||||
|
||||
CardController --> CardService : utilise
|
||||
Factory ..> CardRepository : <<instance de>> construit
|
||||
Factory ..> CardService : construit
|
||||
|
||||
@enduml
|
||||
@@ -0,0 +1,74 @@
|
||||
@startuml
|
||||
' Diagramme de séquence — "Afficher une carte" puis "Révéler la réponse"
|
||||
' Application web Flashcards (SPA/PWA, couche d'accès générique MySQL/Mongo)
|
||||
|
||||
hide footbox
|
||||
|
||||
title Jeu : afficher une carte au hasard puis révéler la réponse
|
||||
|
||||
actor Utilisateur as User
|
||||
participant "SPA React\n(UI)" as SPA
|
||||
participant "CardController\n(API Next.js)" as Api
|
||||
participant "CardService" as Service
|
||||
participant "CardRepository\n(abstraction générique)" as Repo
|
||||
participant "SGBD\n(MySQL OU MongoDB)" as DB
|
||||
|
||||
== Afficher une carte au hasard ==
|
||||
|
||||
User -> SPA : clique « Jouer »
|
||||
SPA -> SPA : un thème est-il déjà sélectionné ?
|
||||
|
||||
alt Thème précis sélectionné (F-04)
|
||||
User -> SPA : sélectionne un thème (ex. javascript)
|
||||
SPA -> Api : GET /api/cards/random?theme=javascript
|
||||
else Tirage global (F-01)
|
||||
SPA -> Api : GET /api/cards/random
|
||||
end
|
||||
|
||||
Api -> Service : playRandom(theme?)
|
||||
activate Service
|
||||
|
||||
alt theme fourni
|
||||
Service -> Repo : findRandomByTheme(theme)
|
||||
else sans thème
|
||||
Service -> Repo : findRandom()
|
||||
end
|
||||
activate Repo
|
||||
|
||||
Repo -> DB : Requête aléatoire (ORDER BY RAND() / $sample)
|
||||
activate DB
|
||||
DB --> Repo : Enregistrement(s) : question, réponse, thème
|
||||
deactivate DB
|
||||
|
||||
Repo --> Service : Card
|
||||
deactivate Repo
|
||||
Service --> Api : Card (réponse non renvoyée par sécurité)
|
||||
deactivate Service
|
||||
Api --> SPA : 200 JSON { id, question, theme }
|
||||
|
||||
SPA -> SPA : affiche la question\nla réponse reste masquée
|
||||
|
||||
== Révéler la réponse ==
|
||||
|
||||
User -> SPA : clique « Voir la réponse » (F-03)
|
||||
SPA -> Api : GET /api/cards/{id}/reveal
|
||||
activate Api
|
||||
Api -> Repo : findById(id)
|
||||
activate Repo
|
||||
Repo -> DB : SELECT par id / findOne
|
||||
activate DB
|
||||
DB --> Repo : Carte complète
|
||||
deactivate DB
|
||||
Repo --> Api : Card { response }
|
||||
deactivate Repo
|
||||
Api --> SPA : 200 JSON { response }
|
||||
deactivate Api
|
||||
|
||||
SPA --> SPA : déroule et affiche la réponse
|
||||
User -> SPA : reclique (masquer/réafficher) — boucle libre
|
||||
loop tant que joueur le souhaite
|
||||
SPA --> User : réponse visible / masquée
|
||||
end
|
||||
|
||||
note over Repo : L'implémentation concrète (MySQL ou MongoDB)\nest fournie par la Factory selon DatabaseConfig\nsans impact sur Service ni Api (générique).
|
||||
@enduml
|
||||
@@ -0,0 +1,45 @@
|
||||
@startuml Usecase
|
||||
' Diagramme de cas d'utilisation — Application web Flashcards (SPA/PWA)
|
||||
' Le CRUD et le jeu sont volontairement isolés : le jeu ne dépend d'aucun cas du catalogue.
|
||||
left to right direction
|
||||
skinparam actorStyle awesome
|
||||
skinparam packageStyle rectangle
|
||||
|
||||
actor "Utilisateur" as User
|
||||
|
||||
rectangle "Jeu — révision" {
|
||||
usecase "Afficher une carte au hasard" as UC_Jouer
|
||||
usecase "Tirer des cartes d'un thème" as UC_Theme
|
||||
usecase "Révéler la réponse" as UC_Revele
|
||||
}
|
||||
|
||||
rectangle "Gestion des cartes (CRUD)" {
|
||||
usecase "Lister les cartes" as UC_Liste
|
||||
usecase "Consulter une carte" as UC_Detail
|
||||
usecase "Créer une carte" as UC_Create
|
||||
usecase "Modifier une carte" as UC_Update
|
||||
usecase "Supprimer une carte" as UC_Delete
|
||||
}
|
||||
|
||||
' --- Jeu ---
|
||||
User --> UC_Jouer
|
||||
UC_Jouer ..> UC_Theme : <<extend>>
|
||||
UC_Jouer --> UC_Revele : <<include>>
|
||||
|
||||
' --- CRUD : la liste est l'entrée unique, le détail est le point d'ancrage des actions ---
|
||||
User --> UC_Liste
|
||||
UC_Liste ..> UC_Detail : <<extend>>
|
||||
UC_Liste ..> UC_Create : <<extend>>
|
||||
UC_Detail ..> UC_Update : <<extend>>
|
||||
UC_Detail ..> UC_Delete : <<extend>>
|
||||
|
||||
note bottom of UC_Delete
|
||||
Suppression avec confirmation
|
||||
end note
|
||||
|
||||
note bottom of UC_Revele
|
||||
La réponse est cachée tant que
|
||||
l'utilisateur ne la déroule pas
|
||||
end note
|
||||
|
||||
@enduml
|
||||
Reference in new issue
Block a user