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,98 @@
|
||||
# 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 | 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(): 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
|
||||
@@ -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
|
||||
@@ -0,0 +1,62 @@
|
||||
# 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 | 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 : 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
|
||||
@@ -0,0 +1,77 @@
|
||||
# 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 | 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 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
|
||||
@@ -0,0 +1,38 @@
|
||||
# Wireframe: Study Flash Cards
|
||||
|
||||
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
|
||||
|
||||
```text
|
||||
+----------------------------------------------------------+ background #B1DDC6
|
||||
| padding 50 px |
|
||||
| +--------------------------------------------------+ |
|
||||
| | | |
|
||||
| | Malay (italic, 40 pt) | | card image 800 x 526
|
||||
| | | | card_front.png (white)
|
||||
| | aku (bold, 60 pt) | | card_back.png (green)
|
||||
| | | |
|
||||
| +--------------------------------------------------+ |
|
||||
| [ X unknown ] [ v known ] | buttons: wrong.png, right.png
|
||||
+----------------------------------------------------------+
|
||||
```
|
||||
|
||||
## Layout
|
||||
|
||||
| Element | Position | Details |
|
||||
| --- | --- | --- |
|
||||
| Window | whole | Title "Flashy", padding 50 px, background `#B1DDC6` |
|
||||
| Card | grid row 0, columns 0 and 1 (both) | `Canvas` 800 x 526, one image, two texts |
|
||||
| Language name | centre of card, y = 150 | Arial 40 italic |
|
||||
| Word | centre of card, y = 263 | Arial 60 bold |
|
||||
| Unknown button | grid row 1, column 0 | `wrong.png`, no border |
|
||||
| Known button | grid row 1, column 1 | `right.png`, no border |
|
||||
|
||||
## States
|
||||
|
||||
| State | Card image | Language name | Word | Text colour |
|
||||
| --- | --- | --- | --- | --- |
|
||||
| Front (first 3000 ms) | `card_front.png` | Malay | the Malay word | black |
|
||||
| Back (after 3000 ms) | `card_back.png` | Danish | the Danish translation | white |
|
||||
| Finished | `card_front.png` | (empty) | "Nothing left to learn" | black |
|
||||
Reference in New Issue
Block a user