Add the plan baseline: business case, stakeholders, plan, design and milestones
Business Case, Stakeholder Analysis, Project Plan, use case chain (UCD, US, UC, DM, SSD, OC, SD, DCD, DICT), three ADRs, milestones MIL-001 to MIL-007, the traceability matrix and 22 review records (autonomous mode, AI as stand-in for S01).
This commit is contained in:
@@ -0,0 +1,170 @@
|
||||
# Sequence Diagrams: Study Flash Cards
|
||||
|
||||
## Metadata
|
||||
| Key | Value |
|
||||
| --- | --- |
|
||||
| ID | SD-001 |
|
||||
| CrossReference | [OC-001], [DCD-001], [DICT-001] |
|
||||
|
||||
## Version History
|
||||
| Date | Status | Author | Reviewer | Change | Commit |
|
||||
| --- | --- | --- | --- | --- | --- |
|
||||
| 2026-10-14 | Accepted | Jens Tirsvad Nielsen | AI as stand-in for S01 | Initial version | pending |
|
||||
|
||||
---
|
||||
|
||||
## Sequence: startStudySession
|
||||
|
||||
**Realizes:** `startStudySession` in [OC-001]
|
||||
|
||||
### Diagram
|
||||
|
||||
```plantuml
|
||||
@startuml
|
||||
participant "main : app" as M
|
||||
participant ":CsvVocabularyRepository" as VR
|
||||
participant ":CsvProgressRepository" as PR
|
||||
participant ":StudySession" as S
|
||||
participant ":Deck" as D
|
||||
participant ":SpeechPort" as SP
|
||||
M -> PR : load()
|
||||
PR --> M : deck | None
|
||||
alt deck is None
|
||||
M -> VR : load()
|
||||
VR --> M : vocabulary
|
||||
create D
|
||||
M -> D : from_vocabulary(vocabulary)
|
||||
D --> M : deck
|
||||
end
|
||||
create S
|
||||
M -> S : create(deck, progress, speech, choose)
|
||||
M -> S : next_card()
|
||||
activate S
|
||||
opt deck is not empty
|
||||
S -> D : draw(choose, exclude)
|
||||
D --> S : card
|
||||
S -> SP : speak(card.front, front_code)
|
||||
end
|
||||
S --> M : CardDto | None
|
||||
deactivate S
|
||||
@enduml
|
||||
```
|
||||
|
||||
### Pattern Annotations
|
||||
|
||||
| Pattern (GRASP / GoF) | Applied to | Rationale |
|
||||
| --- | --- | --- |
|
||||
| Creator | `app.main` creates `StudySession` | It holds the adapters the session needs |
|
||||
| Information Expert | `Deck` draws and removes its own cards | It owns the list of cards |
|
||||
| Null Object | `NullSpeech` as `SpeechPort` | The session never tests for speech |
|
||||
|
||||
### Postcondition Coverage
|
||||
|
||||
| Postcondition (from contract) | Satisfied by message |
|
||||
| --- | --- |
|
||||
| A `StudySession` instance was created | `create(deck, progress, speech, choose)` |
|
||||
| A `Deck` was created from the progress file or a copy of the `Vocabulary` | `PR.load()`, `alt` fragment, `from_vocabulary` |
|
||||
| `current_card` set and a `CardDto` returned, or `None` | `next_card()` with the `opt` fragment |
|
||||
|
||||
### Responsibility Check
|
||||
|
||||
The session coordinates, the deck holds the cards, the repositories hold the file format; no object receives all messages.
|
||||
|
||||
## Sequence: markKnown
|
||||
|
||||
**Realizes:** `markKnown` in [OC-001]
|
||||
|
||||
### Diagram
|
||||
|
||||
```plantuml
|
||||
@startuml
|
||||
participant ":FlashCardView" as V
|
||||
participant ":FlashCardViewModel" as VM
|
||||
participant ":StudySession" as S
|
||||
participant ":Deck" as D
|
||||
participant ":CsvProgressRepository" as PR
|
||||
V -> VM : is_known()
|
||||
activate VM
|
||||
VM -> S : mark_known()
|
||||
activate S
|
||||
opt current_card is not None
|
||||
S -> D : remove(card)
|
||||
S -> PR : save(deck)
|
||||
end
|
||||
deactivate S
|
||||
VM -> S : next_card()
|
||||
S --> VM : CardDto | None
|
||||
VM --> V : side, language name, text
|
||||
deactivate VM
|
||||
@enduml
|
||||
```
|
||||
|
||||
### Pattern Annotations
|
||||
|
||||
| Pattern (GRASP / GoF) | Applied to | Rationale |
|
||||
| --- | --- | --- |
|
||||
| MVVM | `FlashCardView`, `FlashCardViewModel` | The view raises the event and shows the result; the rule is behind the view model |
|
||||
| Repository | `CsvProgressRepository` | The session stores the deck through a port |
|
||||
|
||||
### Postcondition Coverage
|
||||
|
||||
| Postcondition (from contract) | Satisfied by message |
|
||||
| --- | --- |
|
||||
| The card was removed from the `Deck` | `remove(card)` |
|
||||
| The `Deck` was stored | `save(deck)` |
|
||||
| `current_card` was set to `None` | `mark_known()` ends with no current card; `next_card()` then draws the next |
|
||||
|
||||
### Responsibility Check
|
||||
|
||||
The view model only sequences two session calls and maps the result for the view.
|
||||
|
||||
## Sequence: markUnknown
|
||||
|
||||
**Realizes:** `markUnknown` in [OC-001]
|
||||
|
||||
### Diagram
|
||||
|
||||
```plantuml
|
||||
@startuml
|
||||
participant ":FlashCardView" as V
|
||||
participant ":FlashCardViewModel" as VM
|
||||
participant ":StudySession" as S
|
||||
participant ":Deck" as D
|
||||
participant ":SpeechPort" as SP
|
||||
V -> VM : next_card()
|
||||
VM -> S : next_card()
|
||||
activate S
|
||||
opt deck is not empty
|
||||
S -> D : draw(choose, exclude=current)
|
||||
D --> S : card
|
||||
S -> SP : speak(card.front, front_code)
|
||||
end
|
||||
S --> VM : CardDto | None
|
||||
deactivate S
|
||||
VM --> V : side, language name, text
|
||||
@enduml
|
||||
```
|
||||
|
||||
### Pattern Annotations
|
||||
|
||||
| Pattern (GRASP / GoF) | Applied to | Rationale |
|
||||
| --- | --- | --- |
|
||||
| Information Expert | `Deck.draw` | The deck knows its cards |
|
||||
|
||||
### Postcondition Coverage
|
||||
|
||||
| Postcondition (from contract) | Satisfied by message |
|
||||
| --- | --- |
|
||||
| A different card was chosen when two or more exist | `draw(choose, exclude=current)` |
|
||||
| Deck and file unchanged | no `remove` or `save` message |
|
||||
| The Malay word was passed to the `SpeechPort` | `speak(card.front, front_code)` |
|
||||
|
||||
### Responsibility Check
|
||||
|
||||
Same as `markKnown`; the session is the only object that speaks and draws.
|
||||
|
||||
---
|
||||
|
||||
[OC-001]: ./oc.md
|
||||
[DCD-001]: ../dcd.md
|
||||
[DICT-001]: ../dictionary.md
|
||||
Reference in New Issue
Block a user