MIL-008 plan and design: choose level (100, 1000 or all words)
New milestone MIL-008 with story US-001.06, and the design documents updated for the level choice: BC-001, PP-001, US-001, UC-001, DM-001, DICT-001, SSD-001, OC-001, SD-001, DCD-001 and the wireframe. Review records RC-030 to RC-040, all Go (autonomous mode, not independent). Task: MIL-008#1
This commit is contained in:
+127
-99
@@ -1,99 +1,127 @@
|
||||
# Operation Contracts: Study Flash Cards
|
||||
|
||||
## Metadata
|
||||
| Key | Value |
|
||||
| --- | --- |
|
||||
| ID | OC-001 |
|
||||
| CrossReference | [SSD-001], [DM-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 | [c3fbcbc] |
|
||||
|
||||
---
|
||||
|
||||
The turn-over of the card after 3000 ms is started by the system's own timer, not by a message from the Learner, so it has no contract; it is realized in [SD-001].
|
||||
|
||||
## Contract: startStudySession
|
||||
|
||||
| Item | Value |
|
||||
| --- | --- |
|
||||
| Operation | `startStudySession(): CardDto \| None` |
|
||||
| Traces to | `startStudySession` in [SSD-001] |
|
||||
| Domain Model concepts | Study Session, Words To Learn, Word List, Flash Card ([DM-001]); IT terms `StudySession`, `Deck`, `Vocabulary`, `Card` ([DICT-001]) |
|
||||
|
||||
**Preconditions**
|
||||
|
||||
- A `Vocabulary` exists in the word list file.
|
||||
|
||||
**Postconditions**
|
||||
|
||||
- A `StudySession` instance was created.
|
||||
- A `Deck` instance was created and associated with the `StudySession`.
|
||||
- The `Deck` holds the cards of the progress file when it exists, otherwise a copy of the cards of the `Vocabulary`.
|
||||
- When the `Deck` is not empty, `StudySession.current_card` was set to a card of the `Deck` and a `CardDto` of it is returned; otherwise `current_card` is `None` and `None` is returned.
|
||||
|
||||
**Exceptions**
|
||||
|
||||
| Condition (failing precondition) | Outcome |
|
||||
| --- | --- |
|
||||
| The word list file does not exist | `VocabularyNotFoundError` is raised; no session is created |
|
||||
| The word list or progress file has no header of two cells, or a row with other than two cells | `VocabularyFormatError` is raised; no session is created and no file is changed |
|
||||
|
||||
## Contract: markKnown
|
||||
|
||||
| Item | Value |
|
||||
| --- | --- |
|
||||
| Operation | `markKnown(): None` |
|
||||
| Traces to | `markKnown` in [SSD-001] |
|
||||
| Domain Model concepts | Study Session, Words To Learn, Flash Card ([DM-001]); IT terms `StudySession`, `Deck`, `Card` ([DICT-001]) |
|
||||
|
||||
**Preconditions**
|
||||
|
||||
- A `StudySession` exists and its `current_card` is not `None`.
|
||||
|
||||
**Postconditions**
|
||||
|
||||
- The `Card` of `current_card` was removed from the `Deck` (the association was destroyed).
|
||||
- The `Deck` was stored in the progress file.
|
||||
- `StudySession.current_card` was set to `None`.
|
||||
|
||||
**Exceptions**
|
||||
|
||||
| Condition (failing precondition) | Outcome |
|
||||
| --- | --- |
|
||||
| `current_card` is `None` (no card is shown) | Nothing is changed and nothing is stored |
|
||||
|
||||
## Contract: markUnknown
|
||||
|
||||
| Item | Value |
|
||||
| --- | --- |
|
||||
| Operation | `markUnknown(): CardDto \| None` |
|
||||
| Traces to | `markUnknown` in [SSD-001] |
|
||||
| Domain Model concepts | Study Session, Words To Learn, Flash Card ([DM-001]); IT terms `StudySession`, `Deck`, `Card` ([DICT-001]) |
|
||||
|
||||
**Preconditions**
|
||||
|
||||
- A `StudySession` exists.
|
||||
|
||||
**Postconditions**
|
||||
|
||||
- `StudySession.current_card` was set to a card of the `Deck` that differs from the previous `current_card` when the `Deck` holds two or more cards, and a `CardDto` of it is returned.
|
||||
- When the `Deck` is empty, `current_card` is `None` and `None` is returned.
|
||||
- The `Deck` and the progress file are unchanged.
|
||||
- The Malay word of the new `current_card` was passed to the `SpeechPort`.
|
||||
|
||||
**Exceptions**
|
||||
|
||||
| Condition (failing precondition) | Outcome |
|
||||
| --- | --- |
|
||||
| The `Deck` is empty | `None` is returned; nothing is spoken |
|
||||
|
||||
---
|
||||
|
||||
[SSD-001]: ./ssd.md
|
||||
[DM-001]: ../domain-model.md
|
||||
[DICT-001]: ../dictionary.md
|
||||
[SD-001]: ./sd.md
|
||||
[c3fbcbc]: https://git.tirsystem.com/Tirsvad-Udemy-100-days-of-code/031-flash-card/commit/c3fbcbcfaf799e0ae34aed7e14d3bc8a62f03db3
|
||||
# Operation Contracts: Study Flash Cards
|
||||
|
||||
## Metadata
|
||||
| Key | Value |
|
||||
| --- | --- |
|
||||
| ID | OC-001 |
|
||||
| CrossReference | [SSD-001], [DM-001], [DICT-001] |
|
||||
|
||||
## Version History
|
||||
| Date | Status | Author | Reviewer | Change | Commit |
|
||||
| --- | --- | --- | --- | --- | --- |
|
||||
| 2026-10-14 | Deprecated | Jens Tirsvad Nielsen | AI as stand-in for S01 | Initial version | [c3fbcbc] |
|
||||
| 2026-10-14 | Accepted | Jens Tirsvad Nielsen | AI as stand-in for S01 | Added chooseLevel; startStudySession returns the levels | pending |
|
||||
|
||||
---
|
||||
|
||||
The turn-over of the card after 3000 ms is started by the system's own timer, not by a message from the Learner, so it has no contract; it is realized in [SD-001].
|
||||
|
||||
## Contract: startStudySession
|
||||
|
||||
| Item | Value |
|
||||
| --- | --- |
|
||||
| Operation | `startStudySession(): tuple[Level, ...]` |
|
||||
| Traces to | `startStudySession` in [SSD-001] |
|
||||
| Domain Model concepts | Level ([DM-001]); IT term `Level` ([DICT-001]) |
|
||||
|
||||
**Preconditions**
|
||||
|
||||
- The program was started without a level.
|
||||
|
||||
**Postconditions**
|
||||
|
||||
- The levels 100 words, 1000 words and all words are returned, in that order.
|
||||
- No `StudySession` or `Deck` was created and no file was read.
|
||||
|
||||
**Exceptions**
|
||||
|
||||
| Condition (failing precondition) | Outcome |
|
||||
| --- | --- |
|
||||
| The program was started with a level | The operation is not sent; `chooseLevel` is the first operation |
|
||||
|
||||
## Contract: chooseLevel
|
||||
|
||||
| Item | Value |
|
||||
| --- | --- |
|
||||
| Operation | `chooseLevel(level: Level): CardDto \| None` |
|
||||
| Traces to | `chooseLevel` in [SSD-001] |
|
||||
| Domain Model concepts | Study Session, Words To Learn, Word List, Level, Flash Card ([DM-001]); IT terms `StudySession`, `Deck`, `Vocabulary`, `Level`, `Card` ([DICT-001]) |
|
||||
|
||||
**Preconditions**
|
||||
|
||||
- A `Vocabulary` exists in the word list file.
|
||||
- `level` is one of the levels returned by `startStudySession`, or was given at start.
|
||||
|
||||
**Postconditions**
|
||||
|
||||
- A `StudySession` instance was created and associated with `level`.
|
||||
- A `Deck` instance was created and associated with the `StudySession`.
|
||||
- The `Deck` holds the cards of the progress file when it exists, otherwise a copy of the cards of the `Vocabulary`; cards outside the level are kept in it.
|
||||
- The level's cards are the first `level.limit` cards of the `Vocabulary` (all of them when the limit is none or larger than the list).
|
||||
- When the `Deck` holds a card of the level, `StudySession.current_card` was set to such a card and a `CardDto` of it is returned; otherwise `current_card` is `None` and `None` is returned.
|
||||
- The Malay word of the card was passed to the `SpeechPort`.
|
||||
|
||||
**Exceptions**
|
||||
|
||||
| Condition (failing precondition) | Outcome |
|
||||
| --- | --- |
|
||||
| The word list file does not exist | `VocabularyNotFoundError` is raised; no session is created |
|
||||
| The word list or progress file has no header of two cells, or a row with other than two cells | `VocabularyFormatError` is raised; no session is created and no file is changed |
|
||||
| No card of the level is left in the `Deck` | `None` is returned; nothing is spoken |
|
||||
|
||||
## Contract: markKnown
|
||||
|
||||
| Item | Value |
|
||||
| --- | --- |
|
||||
| Operation | `markKnown(): None` |
|
||||
| Traces to | `markKnown` in [SSD-001] |
|
||||
| Domain Model concepts | Study Session, Words To Learn, Flash Card ([DM-001]); IT terms `StudySession`, `Deck`, `Card` ([DICT-001]) |
|
||||
|
||||
**Preconditions**
|
||||
|
||||
- A `StudySession` exists and its `current_card` is not `None`.
|
||||
|
||||
**Postconditions**
|
||||
|
||||
- The `Card` of `current_card` was removed from the `Deck` (the association was destroyed); cards outside the level are not touched.
|
||||
- The whole `Deck` was stored in the progress file.
|
||||
- `StudySession.current_card` was set to `None`.
|
||||
|
||||
**Exceptions**
|
||||
|
||||
| Condition (failing precondition) | Outcome |
|
||||
| --- | --- |
|
||||
| `current_card` is `None` (no card is shown) | Nothing is changed and nothing is stored |
|
||||
|
||||
## Contract: markUnknown
|
||||
|
||||
| Item | Value |
|
||||
| --- | --- |
|
||||
| Operation | `markUnknown(): CardDto \| None` |
|
||||
| Traces to | `markUnknown` in [SSD-001] |
|
||||
| Domain Model concepts | Study Session, Words To Learn, Flash Card ([DM-001]); IT terms `StudySession`, `Deck`, `Card` ([DICT-001]) |
|
||||
|
||||
**Preconditions**
|
||||
|
||||
- A `StudySession` exists.
|
||||
|
||||
**Postconditions**
|
||||
|
||||
- `StudySession.current_card` was set to a card of the level that differs from the previous `current_card` when the level holds two or more cards still to learn, and a `CardDto` of it is returned.
|
||||
- When no card of the level is left, `current_card` is `None` and `None` is returned.
|
||||
- The `Deck` and the progress file are unchanged.
|
||||
- The Malay word of the new `current_card` was passed to the `SpeechPort`.
|
||||
|
||||
**Exceptions**
|
||||
|
||||
| Condition (failing precondition) | Outcome |
|
||||
| --- | --- |
|
||||
| No card of the level is left | `None` is returned; nothing is spoken |
|
||||
|
||||
---
|
||||
|
||||
[SSD-001]: ./ssd.md
|
||||
[DM-001]: ../domain-model.md
|
||||
[DICT-001]: ../dictionary.md
|
||||
[SD-001]: ./sd.md
|
||||
[c3fbcbc]: https://git.tirsystem.com/Tirsvad-Udemy-100-days-of-code/031-flash-card/commit/c3fbcbcfaf799e0ae34aed7e14d3bc8a62f03db3
|
||||
|
||||
+212
-171
@@ -1,171 +1,212 @@
|
||||
# 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 | [c3fbcbc] |
|
||||
|
||||
---
|
||||
|
||||
## 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
|
||||
[c3fbcbc]: https://git.tirsystem.com/Tirsvad-Udemy-100-days-of-code/031-flash-card/commit/c3fbcbcfaf799e0ae34aed7e14d3bc8a62f03db3
|
||||
# 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 | Deprecated | Jens Tirsvad Nielsen | AI as stand-in for S01 | Initial version | [c3fbcbc] |
|
||||
| 2026-10-14 | Accepted | Jens Tirsvad Nielsen | AI as stand-in for S01 | Added the sequences startStudySession (levels) and chooseLevel (level filter) | pending |
|
||||
|
||||
---
|
||||
|
||||
## Sequence: startStudySession
|
||||
|
||||
**Realizes:** `startStudySession` in [OC-001]
|
||||
|
||||
### Diagram
|
||||
|
||||
```plantuml
|
||||
@startuml
|
||||
participant ":LevelView" as V
|
||||
participant ":LevelViewModel" as VM
|
||||
V -> VM : choices
|
||||
VM --> V : tuple[Level, ...]
|
||||
@enduml
|
||||
```
|
||||
|
||||
### Pattern Annotations
|
||||
|
||||
| Pattern (GRASP / GoF) | Applied to | Rationale |
|
||||
| --- | --- | --- |
|
||||
| MVVM | `LevelView`, `LevelViewModel` | The view shows the choices; the labels and the order are in the view model |
|
||||
|
||||
### Postcondition Coverage
|
||||
|
||||
| Postcondition (from contract) | Satisfied by message |
|
||||
| --- | --- |
|
||||
| The three levels are returned in order | `choices` |
|
||||
| No session or deck is created and no file is read | no other message is sent |
|
||||
|
||||
### Responsibility Check
|
||||
|
||||
The view model owns the choices; the view only draws buttons and forwards the click.
|
||||
|
||||
## Sequence: chooseLevel
|
||||
|
||||
**Realizes:** `chooseLevel` in [OC-001]
|
||||
|
||||
### Diagram
|
||||
|
||||
```plantuml
|
||||
@startuml
|
||||
participant "main : app" as M
|
||||
participant ":CsvVocabularyRepository" as VR
|
||||
participant ":CsvProgressRepository" as PR
|
||||
participant "level : Level" as L
|
||||
participant ":StudySession" as S
|
||||
participant ":Deck" as D
|
||||
participant ":SpeechPort" as SP
|
||||
M -> VR : load()
|
||||
VR --> M : vocabulary
|
||||
M -> PR : load()
|
||||
PR --> M : deck | None
|
||||
alt deck is None
|
||||
create D
|
||||
M -> D : from_vocabulary(vocabulary)
|
||||
D --> M : deck
|
||||
end
|
||||
M -> L : first(vocabulary.cards)
|
||||
L --> M : level_cards
|
||||
create S
|
||||
M -> S : create(deck, progress, speech, choose, level_cards)
|
||||
M -> S : next_card()
|
||||
activate S
|
||||
S -> D : within(level_cards)
|
||||
D --> S : candidates
|
||||
opt candidates is not empty
|
||||
S -> D : draw(choose, exclude, among=candidates)
|
||||
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 | `Level.first`, `Deck.within`, `Deck.draw` | The level knows its limit, the deck knows its cards |
|
||||
| Null Object | `NullSpeech` as `SpeechPort` | The session never tests for speech |
|
||||
|
||||
### Postcondition Coverage
|
||||
|
||||
| Postcondition (from contract) | Satisfied by message |
|
||||
| --- | --- |
|
||||
| A `StudySession` was created and associated with the level | `create(deck, progress, speech, choose, level_cards)` |
|
||||
| A `Deck` was created from the progress file or a copy of the `Vocabulary`, cards outside the level kept | `PR.load()`, `alt` fragment, `from_vocabulary` |
|
||||
| The level's cards are the first N cards of the `Vocabulary` | `first(vocabulary.cards)` |
|
||||
| `current_card` set and a `CardDto` returned, or `None`; the word was passed to the `SpeechPort` | `next_card()` with `within`, the `opt` fragment and `speak` |
|
||||
|
||||
### Responsibility Check
|
||||
|
||||
The composition root only wires; the level selects, the deck holds, the session coordinates; 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
|
||||
S -> D : within(level_cards)
|
||||
D --> S : candidates
|
||||
opt candidates is not empty
|
||||
S -> D : draw(choose, exclude=current, among=candidates)
|
||||
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 of the level was chosen when two or more exist | `within(level_cards)`, `draw(choose, exclude=current, among=candidates)` |
|
||||
| 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
|
||||
[c3fbcbc]: https://git.tirsystem.com/Tirsvad-Udemy-100-days-of-code/031-flash-card/commit/c3fbcbcfaf799e0ae34aed7e14d3bc8a62f03db3
|
||||
|
||||
+67
-63
@@ -1,63 +1,67 @@
|
||||
# System Sequence Diagram: Study Flash Cards
|
||||
|
||||
## Metadata
|
||||
| Key | Value |
|
||||
| --- | --- |
|
||||
| ID | SSD-001 |
|
||||
| CrossReference | [UC-001], [DM-001], [OC-001] |
|
||||
| Language | en |
|
||||
| Domain | it |
|
||||
|
||||
## Version History
|
||||
| Date | Status | Author | Reviewer | Change | Commit |
|
||||
| --- | --- | --- | --- | --- | --- |
|
||||
| 2026-10-14 | Accepted | Jens Tirsvad Nielsen | AI as stand-in for S01 | Initial version | [c3fbcbc] |
|
||||
|
||||
---
|
||||
|
||||
## Source Use Case
|
||||
|
||||
Study Flash Cards ([UC-001]) — scenario: main success scenario, with the unknown button as one repetition.
|
||||
|
||||
## Diagram
|
||||
|
||||
```plantuml
|
||||
@startuml
|
||||
actor Learner as L
|
||||
participant ":System" as S
|
||||
L -> S : startStudySession()
|
||||
S --> L : card (word, language name)
|
||||
... 3000 ms pass, the system turns the card over ...
|
||||
S --> L : card (translation, language name)
|
||||
L -> S : markKnown()
|
||||
S --> L : next card (word, language name)
|
||||
L -> S : markUnknown()
|
||||
S --> L : next card (word, language name)
|
||||
@enduml
|
||||
```
|
||||
|
||||
## System Operations
|
||||
|
||||
| Step | Message | Parameters | Return | Use case step |
|
||||
| --- | --- | --- | --- | --- |
|
||||
| 1 | startStudySession | none | card to show, or "nothing left to learn" | 1, 2, 3 |
|
||||
| 2 | (timer) turn the card over | none | the same card, translation side | 4 |
|
||||
| 3 | markKnown | none | next card, or "nothing left to learn" | 5, 6, 7 |
|
||||
| 4 | markUnknown | none | next card | 5a, 7 |
|
||||
|
||||
The turn-over in step 2 is started by the system's own timer, not by a message from the Learner; it is shown as a return without a call, which is the one deviation from "every return answers a message".
|
||||
|
||||
## Alternate Flows
|
||||
|
||||
The extensions 2a, 3a, 5b and 7a of [UC-001] add no system operation of their own (they are errors, speech and timer handling inside the three operations above); their behaviour is in [OC-001] as exceptions. They are out of scope of this diagram, which shows the main success scenario with `markUnknown` as the one alternate answer.
|
||||
|
||||
## Lifecycle Notes
|
||||
|
||||
The system instance lives for one run of the program. The words to learn are created when the session starts and saved after each `markKnown`.
|
||||
|
||||
---
|
||||
|
||||
[UC-001]: ./uc.md
|
||||
[DM-001]: ../domain-model.md
|
||||
[OC-001]: ./oc.md
|
||||
[c3fbcbc]: https://git.tirsystem.com/Tirsvad-Udemy-100-days-of-code/031-flash-card/commit/c3fbcbcfaf799e0ae34aed7e14d3bc8a62f03db3
|
||||
# System Sequence Diagram: Study Flash Cards
|
||||
|
||||
## Metadata
|
||||
| Key | Value |
|
||||
| --- | --- |
|
||||
| ID | SSD-001 |
|
||||
| CrossReference | [UC-001], [DM-001], [OC-001] |
|
||||
| Language | en |
|
||||
| Domain | it |
|
||||
|
||||
## Version History
|
||||
| Date | Status | Author | Reviewer | Change | Commit |
|
||||
| --- | --- | --- | --- | --- | --- |
|
||||
| 2026-10-14 | Deprecated | Jens Tirsvad Nielsen | AI as stand-in for S01 | Initial version | [c3fbcbc] |
|
||||
| 2026-10-14 | Accepted | Jens Tirsvad Nielsen | AI as stand-in for S01 | Added chooseLevel; startStudySession returns the levels | pending |
|
||||
|
||||
---
|
||||
|
||||
## Source Use Case
|
||||
|
||||
Study Flash Cards ([UC-001]) — scenario: main success scenario, with the unknown button as one repetition.
|
||||
|
||||
## Diagram
|
||||
|
||||
```plantuml
|
||||
@startuml
|
||||
actor Learner as L
|
||||
participant ":System" as S
|
||||
L -> S : startStudySession()
|
||||
S --> L : levels (100 words, 1000 words, all words)
|
||||
L -> S : chooseLevel(level)
|
||||
S --> L : card (word, language name)
|
||||
... 3000 ms pass, the system turns the card over ...
|
||||
S --> L : card (translation, language name)
|
||||
L -> S : markKnown()
|
||||
S --> L : next card (word, language name)
|
||||
L -> S : markUnknown()
|
||||
S --> L : next card (word, language name)
|
||||
@enduml
|
||||
```
|
||||
|
||||
## System Operations
|
||||
|
||||
| Step | Message | Parameters | Return | Use case step |
|
||||
| --- | --- | --- | --- | --- |
|
||||
| 1 | startStudySession | none | the levels to choose from | 1, 2 |
|
||||
| 2 | chooseLevel | level | card to show, or "nothing left to learn" | 3, 4, 5 |
|
||||
| 3 | (timer) turn the card over | none | the same card, translation side | 6 |
|
||||
| 4 | markKnown | none | next card, or "nothing left to learn" | 7, 8, 9 |
|
||||
| 5 | markUnknown | none | next card, or "nothing left to learn" | 7a, 9 |
|
||||
|
||||
The turn-over in step 3 is started by the system's own timer, not by a message from the Learner; it is shown as a return without a call, which is the one deviation from "every return answers a message". When the level is given at start (extension 3a of [UC-001]) the Learner's first message is `chooseLevel` and `startStudySession` is not sent.
|
||||
|
||||
## Alternate Flows
|
||||
|
||||
The extensions 3a, 4a, 5a, 7b and 9a of [UC-001] add no system operation of their own (they are errors, speech, timer and level handling inside the operations above); their behaviour is in [OC-001] as exceptions. They are out of scope of this diagram, which shows the main success scenario with `markUnknown` as the one alternate answer.
|
||||
|
||||
## Lifecycle Notes
|
||||
|
||||
The system instance lives for one run of the program. The words to learn are created when the level is chosen and saved after each `markKnown`.
|
||||
|
||||
---
|
||||
|
||||
[UC-001]: ./uc.md
|
||||
[DM-001]: ../domain-model.md
|
||||
[OC-001]: ./oc.md
|
||||
[c3fbcbc]: https://git.tirsystem.com/Tirsvad-Udemy-100-days-of-code/031-flash-card/commit/c3fbcbcfaf799e0ae34aed7e14d3bc8a62f03db3
|
||||
|
||||
+86
-78
@@ -1,78 +1,86 @@
|
||||
# UC-001: Study Flash Cards
|
||||
|
||||
## Metadata
|
||||
| Key | Value |
|
||||
| --- | --- |
|
||||
| ID | UC-001 |
|
||||
| CrossReference | [UCD-001], [US-001], [SA-001], [DM-001], [SSD-001] |
|
||||
| Language | en |
|
||||
| Domain | it |
|
||||
|
||||
## Version History
|
||||
| Date | Status | Author | Reviewer | Change | Commit |
|
||||
| --- | --- | --- | --- | --- | --- |
|
||||
| 2026-10-14 | Accepted | Jens Tirsvad Nielsen | AI as stand-in for S01 | Initial version | [c3fbcbc] |
|
||||
|
||||
---
|
||||
|
||||
**Format:** Fully Dressed
|
||||
|
||||
## Fully Dressed
|
||||
|
||||
- **Scope:** Flash Card program
|
||||
- **Level:** user-goal
|
||||
- **Primary Actor:** Learner
|
||||
- **Stakeholders and Interests:**
|
||||
- S01 — learns the Malay words and wants only unknown words to come up
|
||||
- S02 — wants to see the assignment's behaviour step by step
|
||||
- **Preconditions:**
|
||||
- A word list exists.
|
||||
- A display is available.
|
||||
- **Postconditions (success guarantee):**
|
||||
- The words the Learner marked as known are no longer in the words to learn.
|
||||
- The words to learn are kept, so that the next session starts from them.
|
||||
|
||||
### Main Success Scenario
|
||||
|
||||
1. The Learner starts the program.
|
||||
2. The system loads the words to learn: from the kept progress when it exists, otherwise from the word list.
|
||||
3. The system shows a random card with the word in Malay.
|
||||
4. After three seconds the system turns the card over and shows the translation in Danish.
|
||||
5. The Learner states that the word is known.
|
||||
6. The system removes the word from the words to learn and keeps the words to learn.
|
||||
7. The system shows a new random card, and the Learner repeats from step 4 until no word is left.
|
||||
|
||||
### Extensions (Alternative / Exception Flows)
|
||||
|
||||
- 3a. Spoken words are available on the Learner's machine:
|
||||
1. The system speaks the Malay word. If speaking fails, the system logs it and goes on.
|
||||
- 5a. The Learner states that the word is not known:
|
||||
1. The system keeps the word in the words to learn and shows a new random card; the Learner goes on at step 4.
|
||||
- 5b. The Learner answers before three seconds have passed:
|
||||
1. The system cancels the turn-over of the card being shown and starts a new one for the next card.
|
||||
- 7a. No word is left:
|
||||
1. The system tells the Learner that there is nothing left to learn, and further answers change nothing.
|
||||
- 2a. The kept progress or the word list is unreadable:
|
||||
1. The system reports the problem to the Learner and ends; it does not overwrite the kept progress.
|
||||
|
||||
### Special Requirements / Business Rules
|
||||
|
||||
| Step | Rule |
|
||||
| --- | --- |
|
||||
| 3, 7 | The next card is chosen at random from the words to learn |
|
||||
| 4 | The turn-over comes three seconds after the card appears |
|
||||
| 6 | A word is identified by its Malay and Danish text; the first equal word is removed |
|
||||
| 2 | The word list names its two languages and holds one word and one translation per card |
|
||||
|
||||
### Open Issues
|
||||
|
||||
- Starting again (resetting the kept progress) is not offered in the program; deleting the kept progress does it.
|
||||
|
||||
---
|
||||
|
||||
[UCD-001]: ../use-case-diagram.md
|
||||
[US-001]: ../user-stories.md
|
||||
[SA-001]: ../stakeholder-analysis.md
|
||||
[DM-001]: ../domain-model.md
|
||||
[SSD-001]: ./ssd.md
|
||||
[c3fbcbc]: https://git.tirsystem.com/Tirsvad-Udemy-100-days-of-code/031-flash-card/commit/c3fbcbcfaf799e0ae34aed7e14d3bc8a62f03db3
|
||||
# UC-001: Study Flash Cards
|
||||
|
||||
## Metadata
|
||||
| Key | Value |
|
||||
| --- | --- |
|
||||
| ID | UC-001 |
|
||||
| CrossReference | [UCD-001], [US-001], [SA-001], [DM-001], [SSD-001] |
|
||||
| Language | en |
|
||||
| Domain | it |
|
||||
|
||||
## Version History
|
||||
| Date | Status | Author | Reviewer | Change | Commit |
|
||||
| --- | --- | --- | --- | --- | --- |
|
||||
| 2026-10-14 | Deprecated | Jens Tirsvad Nielsen | AI as stand-in for S01 | Initial version | [c3fbcbc] |
|
||||
| 2026-10-14 | Accepted | Jens Tirsvad Nielsen | AI as stand-in for S01 | Added the choice of level (US-001.06) | pending |
|
||||
|
||||
---
|
||||
|
||||
**Format:** Fully Dressed
|
||||
|
||||
## Fully Dressed
|
||||
|
||||
- **Scope:** Flash Card program
|
||||
- **Level:** user-goal
|
||||
- **Primary Actor:** Learner
|
||||
- **Stakeholders and Interests:**
|
||||
- S01 — learns the Malay words and wants only unknown words to come up
|
||||
- S02 — wants to see the assignment's behaviour step by step
|
||||
- **Preconditions:**
|
||||
- A word list exists.
|
||||
- A display is available.
|
||||
- **Postconditions (success guarantee):**
|
||||
- The words the Learner marked as known are no longer in the words to learn.
|
||||
- The words to learn are kept, so that the next session starts from them.
|
||||
|
||||
### Main Success Scenario
|
||||
|
||||
1. The Learner starts the program.
|
||||
2. The system offers the levels: 100 words, 1000 words and all words.
|
||||
3. The Learner chooses a level.
|
||||
4. The system loads the words to learn: from the kept progress when it exists, otherwise from the word list.
|
||||
5. The system shows a random card, with the word in Malay, from the first words of the word list that fit the level and are still to learn.
|
||||
6. After three seconds the system turns the card over and shows the translation in Danish.
|
||||
7. The Learner states that the word is known.
|
||||
8. The system removes the word from the words to learn and keeps the words to learn.
|
||||
9. The system shows a new random card of the level, and the Learner repeats from step 6 until no word is left at the level.
|
||||
|
||||
### Extensions (Alternative / Exception Flows)
|
||||
|
||||
- 3a. The Learner has given the level when starting the program:
|
||||
1. The system skips steps 2 and 3 and goes on at step 4.
|
||||
- 5a. Spoken words are available on the Learner's machine:
|
||||
1. The system speaks the Malay word. If speaking fails, the system logs it and goes on.
|
||||
- 7a. The Learner states that the word is not known:
|
||||
1. The system keeps the word in the words to learn and shows a new random card of the level; the Learner goes on at step 6.
|
||||
- 7b. The Learner answers before three seconds have passed:
|
||||
1. The system cancels the turn-over of the card being shown and starts a new one for the next card.
|
||||
- 9a. No word is left at the level:
|
||||
1. The system tells the Learner that there is nothing left to learn at this level, and further answers change nothing.
|
||||
- 4a. The kept progress or the word list is unreadable:
|
||||
1. The system reports the problem to the Learner and ends; it does not overwrite the kept progress.
|
||||
|
||||
### Special Requirements / Business Rules
|
||||
|
||||
| Step | Rule |
|
||||
| --- | --- |
|
||||
| 2, 3 | A level is a number of words (100 or 1000) or all words |
|
||||
| 5 | The word list is ordered from the most to the least frequent word; a level of N words is its first N words; a list shorter than N is used whole |
|
||||
| 5, 9 | The next card is chosen at random from the words of the level that are still to learn |
|
||||
| 6 | The turn-over comes three seconds after the card appears |
|
||||
| 8 | A word is identified by its Malay and Danish text; the first equal word is removed; known words stay known at every level and words outside the level are kept |
|
||||
| 4 | The word list names its two languages and holds one word and one translation per card |
|
||||
|
||||
### Open Issues
|
||||
|
||||
- Starting again (resetting the kept progress) is not offered in the program; deleting the kept progress does it.
|
||||
- Going back to the level choice without restarting the program is not offered.
|
||||
|
||||
---
|
||||
|
||||
[UCD-001]: ../use-case-diagram.md
|
||||
[US-001]: ../user-stories.md
|
||||
[SA-001]: ../stakeholder-analysis.md
|
||||
[DM-001]: ../domain-model.md
|
||||
[SSD-001]: ./ssd.md
|
||||
[c3fbcbc]: https://git.tirsystem.com/Tirsvad-Udemy-100-days-of-code/031-flash-card/commit/c3fbcbcfaf799e0ae34aed7e14d3bc8a62f03db3
|
||||
|
||||
@@ -1,8 +1,32 @@
|
||||
# Wireframe: Study Flash Cards
|
||||
|
||||
_Revision 2026-10-14: the level screen (screen 1) was added for US-001.06. It was drawn by the AI from the use case because the Product Owner gave no wireframe for it; S01 may change it._
|
||||
|
||||
The Product Owner gave this screen in the first prompt (the course's target screenshot). The presentation layer implements it and does not redesign it. Source use case: [UC-001](./uc.md).
|
||||
|
||||
## Screen
|
||||
## Screen 1: Choose your level
|
||||
|
||||
```text
|
||||
+----------------------------------------------------------+ background #B1DDC6
|
||||
| padding 50 px |
|
||||
| |
|
||||
| Choose your level (Arial 40 italic) |
|
||||
| |
|
||||
| [ 100 words ] |
|
||||
| [ 1000 words ] |
|
||||
| [ All words ] |
|
||||
| |
|
||||
+----------------------------------------------------------+
|
||||
```
|
||||
|
||||
| Element | Position | Details |
|
||||
| --- | --- | --- |
|
||||
| Window | whole | Same title, padding and background as the card screen |
|
||||
| Title | row 0 | "Choose your level", Arial 40 italic |
|
||||
| Level buttons | rows 1 to 3, one column | Labels "100 words", "1000 words", "All words"; Arial 24 bold; white background, equal width |
|
||||
| After a choice | whole | The screen is replaced by screen 2 on the same window |
|
||||
|
||||
## Screen 2: The card
|
||||
|
||||
```text
|
||||
+----------------------------------------------------------+ background #B1DDC6
|
||||
|
||||
Reference in New Issue
Block a user