diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml
new file mode 100644
index 0000000..6be6cfe
--- /dev/null
+++ b/.github/workflows/ci.yml
@@ -0,0 +1,26 @@
+# Runs on GitHub Actions and on Gitea Actions (Gitea also reads .github/workflows).
+name: CI
+
+on:
+ push:
+ pull_request:
+
+jobs:
+ test:
+ runs-on: ubuntu-latest
+ steps:
+ - uses: actions/checkout@v4
+ - uses: actions/setup-python@v5
+ with:
+ python-version: "3.13"
+ - name: Install
+ run: |
+ python -m venv .venv
+ .venv/bin/python -m pip install --upgrade pip
+ .venv/bin/python -m pip install -e ".[dev]"
+ - name: Lint
+ run: .venv/bin/ruff check .
+ - name: Type check
+ run: .venv/bin/mypy
+ - name: Test
+ run: .venv/bin/python -m pytest
diff --git a/.gitignore b/.gitignore
new file mode 100644
index 0000000..ef1a1da
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1,179 @@
+# ---> Python
+# Byte-compiled / optimized / DLL files
+__pycache__/
+*.py[cod]
+*$py.class
+
+# C extensions
+*.so
+
+# Distribution / packaging
+.Python
+build/
+develop-eggs/
+dist/
+downloads/
+eggs/
+.eggs/
+lib/
+lib64/
+parts/
+sdist/
+var/
+wheels/
+share/python-wheels/
+*.egg-info/
+.installed.cfg
+*.egg
+MANIFEST
+
+# PyInstaller
+# Usually these files are written by a python script from a template
+# before PyInstaller builds the exe, so as to inject date/other infos into it.
+*.manifest
+*.spec
+
+# Installer logs
+pip-log.txt
+pip-delete-this-directory.txt
+
+# Unit test / coverage reports
+htmlcov/
+.tox/
+.nox/
+.coverage
+.coverage.*
+.cache
+nosetests.xml
+coverage.xml
+*.cover
+*.py,cover
+.hypothesis/
+.pytest_cache/
+cover/
+
+# Translations
+*.mo
+*.pot
+
+# Django stuff:
+*.log
+local_settings.py
+db.sqlite3
+db.sqlite3-journal
+
+# Flask stuff:
+instance/
+.webassets-cache
+
+# Scrapy stuff:
+.scrapy
+
+# Sphinx documentation
+docs/_build/
+
+# PyBuilder
+.pybuilder/
+target/
+
+# Jupyter Notebook
+.ipynb_checkpoints
+
+# IPython
+profile_default/
+ipython_config.py
+
+# pyenv
+# For a library or package, you might want to ignore these files since the code is
+# intended to run in multiple environments; otherwise, check them in:
+# .python-version
+
+# pipenv
+# According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control.
+# However, in case of collaboration, if having platform-specific dependencies or dependencies
+# having no cross-platform support, pipenv may install dependencies that don't work, or not
+# install all needed dependencies.
+#Pipfile.lock
+
+# UV
+# Similar to Pipfile.lock, it is generally recommended to include uv.lock in version control.
+# This is especially recommended for binary packages to ensure reproducibility, and is more
+# commonly ignored for libraries.
+#uv.lock
+
+# poetry
+# Similar to Pipfile.lock, it is generally recommended to include poetry.lock in version control.
+# This is especially recommended for binary packages to ensure reproducibility, and is more
+# commonly ignored for libraries.
+# https://python-poetry.org/docs/basic-usage/#commit-your-poetrylock-file-to-version-control
+#poetry.lock
+
+# pdm
+# Similar to Pipfile.lock, it is generally recommended to include pdm.lock in version control.
+#pdm.lock
+# pdm stores project-wide configurations in .pdm.toml, but it is recommended to not include it
+# in version control.
+# https://pdm.fming.dev/latest/usage/project/#working-with-version-control
+.pdm.toml
+.pdm-python
+.pdm-build/
+
+# PEP 582; used by e.g. github.com/David-OConnor/pyflow and github.com/pdm-project/pdm
+__pypackages__/
+
+# Celery stuff
+celerybeat-schedule
+celerybeat.pid
+
+# SageMath parsed files
+*.sage.py
+
+# Environments
+.env
+.venv
+env/
+venv/
+ENV/
+env.bak/
+venv.bak/
+
+# Spyder project settings
+.spyderproject
+.spyproject
+
+# Rope project settings
+.ropeproject
+
+# mkdocs documentation
+/site
+
+# mypy
+.mypy_cache/
+.dmypy.json
+dmypy.json
+
+# Pyre type checker
+.pyre/
+
+# pytype static type analyzer
+.pytype/
+
+# Cython debug symbols
+cython_debug/
+
+# PyCharm
+# JetBrains specific template is maintained in a separate JetBrains.gitignore that can
+# be found at https://github.com/github/gitignore/blob/main/Global/JetBrains.gitignore
+# and can be added to the global gitignore or merged into this file. For a more nuclear
+# option (not recommended) you can uncomment the following to ignore the entire idea folder.
+#.idea/
+
+# Ruff stuff:
+.ruff_cache/
+
+# PyPI configuration file
+.pypirc
+
+
+# Doxygen output
+docs/doxygen/
diff --git a/.gitmodules b/.gitmodules
new file mode 100644
index 0000000..a759dc9
--- /dev/null
+++ b/.gitmodules
@@ -0,0 +1,3 @@
+[submodule "framework"]
+ path = framework
+ url = ssh://git@git.tirsystem.com:10022/TirSystem/SQA-QC-Framework.git
diff --git a/Doxyfile b/Doxyfile
new file mode 100644
index 0000000..93f7d48
--- /dev/null
+++ b/Doxyfile
@@ -0,0 +1,17 @@
+# Doxygen configuration for the coffee machine (Python source with Doxygen comments).
+# Build with: doxygen Doxyfile (output goes to docs/doxygen/, which is ignored by git)
+PROJECT_NAME = "OOP Coffee Machine"
+PROJECT_BRIEF = "Udemy 100 Days of Code: object-oriented coffee machine"
+OUTPUT_DIRECTORY = docs/doxygen
+INPUT = src README.md
+USE_MDFILE_AS_MAINPAGE = README.md
+FILE_PATTERNS = *.py *.md
+RECURSIVE = YES
+OPTIMIZE_OUTPUT_JAVA = YES
+EXTRACT_ALL = YES
+EXTRACT_PRIVATE = NO
+GENERATE_HTML = YES
+GENERATE_LATEX = NO
+QUIET = YES
+WARN_IF_UNDOCUMENTED = YES
+WARN_AS_ERROR = NO
diff --git a/docs/artifact-registry.md b/docs/artifact-registry.md
new file mode 100644
index 0000000..ebbcb56
--- /dev/null
+++ b/docs/artifact-registry.md
@@ -0,0 +1,59 @@
+# Artifact Registry
+
+This project's artifact state. Types, short names and `CrossReference
+Candidates` come from the framework catalog
+(`framework/registry/artifact-catalog.md`); this file only records where
+each document lives in *this* project and the next version to use.
+
+Delete rows for types you don't use. Add a row the first time you create a
+document of a type. `Primary File` may contain a glob (e.g.
+`docs/uc-*/uc.md`); `framework/scripts/find-crossreferences.sh` reads it.
+
+| Short Name | Artifact Type | Primary File | Next Available Version |
+| --- | --- | --- | --- |
+| BC | Business Case | docs/business-case.md | 002 |
+| SA | Stakeholder Analysis | docs/stakeholder-analysis.md | 002 |
+| PP | Project Plan | docs/project-plan.md | 002 |
+| MIL | Milestone / Gateway | docs/milestones/mil-*.md | 004 |
+| RC | SQA Review Record | docs/sqa/reviews/rc-*.md | 007 |
+| TM | Traceability Matrix | docs/sqa/traceability-matrix.md | 002 |
+
+## Languages
+
+Set the PO language when the project starts; `project-planning` asks for it
+if it is missing. An artifact of a type marked "Written in the PO language"
+exists once, in that language, under its normal name (`business-case.md`); the
+`artifact` skill ("One file per artifact") has the rule.
+
+| Setting | Value |
+| --- | --- |
+| PO language | en |
+| PO domain | it |
+| High-level register | IT Executive English |
+| Technical register | IT Professional English |
+
+Every artifact of a type marked "Yes" below states its language and domain in
+its `Language` and `Domain` Metadata rows; `new-artifact.sh` fills them from
+`PO language` and `PO domain`. `Language` is a BCP 47 code (`da`, `en`).
+`Domain` is a value from this list; add a row to introduce a domain, so a
+reviewer can see at once which professional vocabulary a document uses.
+
+| Domain | Meaning |
+| --- | --- |
+| it | Software and IT |
+| medical | Healthcare and medical devices |
+| construction | Construction and civil engineering |
+
+| Artifact types | Register | Written in the PO language |
+| --- | --- | --- |
+| BC, KPI, PP, MIL | IT Executive English | Yes |
+| SA, BMC, BPMN, UCD, US, UC, SSD, DM, RA, GOV, DICT | IT Professional English | Yes |
+| OC, SD, DCD, ERD, ADR, TM, RC, QC, source code | IT Professional English | No |
+
+## Notes
+
+- "Next Available Version" is the zero-padded (3-digit) version to use the
+ *next* time a new document of that type is created. Increment it only when
+ a brand-new document is created, not when an existing document's
+ `## Version History` gets a row.
+- `ADR` uses 4 digits (`0001`); `RC` is sequential across all artifact types.
diff --git a/docs/business-case.md b/docs/business-case.md
new file mode 100644
index 0000000..9e3d60b
--- /dev/null
+++ b/docs/business-case.md
@@ -0,0 +1,139 @@
+# Business Case: OOP Coffee Machine
+
+## Metadata
+| Key | Value |
+| --- | --- |
+| ID | BC-001 |
+| CrossReference | [SA-001], [PP-001] |
+| Language | en |
+| Domain | it |
+
+## Version History
+| Date | Status | Author | Reviewer | Change | Commit |
+| --- | --- | --- | --- | --- | --- |
+| 2026-10-07 | Deprecated | Jens Tirsvad Nielsen | S01 | Initial version | [c24f412] |
+| 2026-10-07 | Accepted | Jens Tirsvad Nielsen | S01 | Fixed Cost-Benefit justification and added completion constraint
Accepted after RC-001 (Go) | [c24f412] |
+
+---
+
+## Executive Summary
+
+The Udemy course "100 Days of Code: The Complete Python Pro Bootcamp" asks
+participants to build an object-oriented coffee machine program that uses
+`Menu`, `CoffeeMaker` and `MoneyMachine` classes. This project delivers that
+assignment as a small, readable, runnable Python repository that other course
+participants and GitHub visitors can use as a reference solution.
+
+## Methodological and Standards Foundation
+
+Quality characteristics follow ISO/IEC 25010:2023. Planning follows the
+framework in `framework/`: Business Case, Stakeholder Analysis, Project Plan,
+milestones, tasks synced as issues, then code. Code follows the
+`coding-conventions` skill (Python) and is reviewed against its
+`qc-programming-*` checklist.
+
+## Problem Statement
+
+The course assignment is solved privately in the lesson editor. There is no
+reproducible repository with tests, documentation and run instructions that a
+fellow participant can clone and run, or that a GitHub visitor can browse.
+
+## Business Opportunity
+
+A clean, tested and documented repository lets participants compare solutions
+and lets viewers find ideas, at the cost of a few hours of work.
+
+## Objectives
+
+1. Deliver a coffee machine program with the assignment's class and method names.
+2. Cover the behaviour with automated pytest tests.
+3. Document how to set up, run and test the project on Windows, Debian Linux and macOS.
+4. Publish the repository with a description, topics and a README.
+
+## Scope
+
+### In Scope
+
+- Python 3.13+ package under `src/`, tests under `tests/`, documents under `docs/`.
+- `pyproject.toml`, Python `.gitignore`, `constants.py`, Doxygen comments and a `Doxyfile`.
+- A README following the course template, including `.venv` and `pip` instructions.
+- Repository description and topics on the git host.
+
+### Out of Scope
+
+- Runtime dependencies, a GUI or a database.
+- Committing, pushing or merging by the assistant (the Product Owner does this).
+- Reading or testing the `.env` file from the project code.
+
+## Expected Benefits
+
+### Tangible Benefits
+
+- A runnable program and a passing test suite.
+- A README that reproduces setup in under five minutes.
+
+### Intangible Benefits
+
+- Practice of object-oriented design and a documented workflow.
+- A reference other participants can learn from.
+
+## Strategic Alignment
+
+The project supports the Product Owner's learning goal of completing the
+100 Days of Code bootcamp with a professional working method.
+
+## Success Criteria
+
+| # | Criterion | Target | Measure |
+| --- | --- | --- | --- |
+| 1 | Tests pass | 100 % of tests green | `pytest` exit code 0 |
+| 2 | Runtime dependencies | 0 | `[project] dependencies` in `pyproject.toml` is empty |
+| 3 | Setup reproducible | README steps work on a clean clone | Product Owner follows the README once |
+| 4 | Assignment names kept | `get_items`, `find_drink`, `is_resource_sufficient`, `make_payment`, `make_coffee`, `report` present | Review of source |
+| 5 | Repository presentable | Description and at least 3 topics set | Check on the git host |
+
+## Risks
+
+| Risk | Impact | Mitigation |
+| --- | --- | --- |
+| Token in `.env` leaks into the repository | High | `.env` stays in `.gitignore`; the code never reads it; it is used only for the sync tool |
+| Tests drift from the assignment behaviour | Medium | Tests are written from the assignment text and reviewed against `qc-programming-python` |
+| Doxygen is not installed on a viewer's machine | Low | The README documents the optional install; docs are not needed to run |
+
+## Assumptions
+
+- Python 3.13 or newer is available on the Product Owner's machine.
+- The git host accepts the API token in `.env` for the sync.
+
+## Constraints
+
+- Python greater than 3.13, `venv`, `pytest`, `pyproject.toml`.
+- Constants live in `constants.py`; source comments use Doxygen style.
+- Folder structure `src/`, `tests/`, `docs/`; pull requests per step.
+- Target completion 2026-10-16, the end of the last phase in [PP-001].
+
+## Cost–Benefit Assessment
+
+| Costs | Benefits |
+| --- | --- |
+| A few hours of the Product Owner's time; no licence or hosting cost | Reusable reference repository and a documented working method |
+
+The assessment is qualitative on purpose: this is a personal learning project with no revenue, budget or monetary cost to quantify.
+
+## Stakeholders
+
+| Stakeholder ID (SA) | Interest in this project |
+| --- | --- |
+| S01 | Completes the assignment with a professional method |
+| S02 | Wants readable, runnable code and instructions |
+| S03 | Wants a clear description, topics and README |
+
+## Recommendation
+
+Proceed — the scope is small, has no runtime dependencies and gives a lasting reference repository.
+
+---
+
+[SA-001]: ./stakeholder-analysis.md
+[PP-001]: ./project-plan.md
+[c24f412]: https://git.tirsystem.com/Tirsvad-Udemy-100_days_of_code/016-oop_coffee_machine/commit/c24f41207fb15f39b0ad6501e1f3126d3bd9232e
diff --git a/docs/milestones/mil-001-setup.md b/docs/milestones/mil-001-setup.md
new file mode 100644
index 0000000..ce3a251
--- /dev/null
+++ b/docs/milestones/mil-001-setup.md
@@ -0,0 +1,75 @@
+# Phase 1: Project Setup
+
+## Metadata
+| Key | Value |
+| --- | --- |
+| ID | MIL-001 |
+| CrossReference | [BC-001], [SA-001], [PP-001] |
+| Language | en |
+| Domain | it |
+
+## Version History
+| Date | Status | Author | Reviewer | Change | Commit |
+| --- | --- | --- | --- | --- | --- |
+| 2026-10-07 | Deprecated | Jens Tirsvad Nielsen | S01 | Initial version | [c24f412] |
+| 2026-10-07 | Accepted | Jens Tirsvad Nielsen | S01 | Accepted after RC-003 (Go) | [c24f412] |
+
+---
+
+## Purpose
+
+Decide whether the project skeleton, tooling and configuration are ready so that application code can be written on top of them.
+
+## Deliverable
+
+Repository skeleton with `pyproject.toml`, Python `.gitignore`, `src/`, `tests/`, `constants.py`, `Doxyfile` and a CI workflow that runs pytest.
+
+## Go / No-Go Criteria
+
+| # | Criterion (objectively checkable) | Go | No-Go |
+| --- | --- | --- | --- |
+| 1 | `pip install -e .[dev]` succeeds in a fresh `.venv` on Python 3.13+ | Met | Not met |
+| 2 | `pytest` runs (collects zero or more tests) without configuration errors | Met | Not met |
+| 3 | `[project] dependencies` in `pyproject.toml` is empty | Met | Not met |
+| 4 | `.env` and `.venv` are ignored by `.gitignore` | Met | Not met |
+| 5 | `doxygen Doxyfile` runs without errors | Met | Not met |
+
+## Dependencies
+
+| Depends on | Reason |
+| --- | --- |
+| None | First phase |
+
+## Traceability
+
+| Business Case objective / KPI / user story | Reference |
+| --- | --- |
+| Objectives 2 and 3; success criteria 1 and 2 | [BC-001] |
+
+## Ownership
+
+| Role | Stakeholder ID (SA) |
+| --- | --- |
+| Owner | S01 |
+| Approving reviewer | S01 |
+
+## Target Date
+
+2026-10-09 — start of the course project, no external deadline.
+
+## Tasks
+
+| # | Task | Summary | Needs its own Use Case/User Story? | Reference |
+| --- | --- | --- | --- | --- |
+| 1 | Add pyproject.toml | Configure the project with `requires-python >= 3.13`, a `src/` layout, no runtime dependencies and pytest as an optional `dev` dependency, so that setup is reproducible for S02. | No | |
+| 2 | Review Python .gitignore | Confirm the Python `.gitignore` ignores `.venv/`, `.env`, caches and generated Doxygen output so tokens and build artefacts never reach the repository (risk in BC-001). | No | |
+| 3 | Create src and tests skeleton with constants.py | Create `src/coffee_machine/` with `__init__.py` and `constants.py` (menu data, resources, coin values, command words) and an empty `tests/` package, following the coding conventions. | No | |
+| 4 | Add Doxyfile | Add a Doxyfile configured for Python (`OPTIMIZE_OUTPUT_JAVA`, input `src/`, output `docs/api/`) so Doxygen comments in the source can be built into documentation. | No | |
+| 5 | Configure CI workflow | Add a CI workflow for the git host that creates a venv, installs the project with the `dev` extra and runs pytest on Python 3.13, to be described in the README. | No | |
+
+---
+
+[BC-001]: ../business-case.md
+[SA-001]: ../stakeholder-analysis.md
+[PP-001]: ../project-plan.md
+[c24f412]: https://git.tirsystem.com/Tirsvad-Udemy-100_days_of_code/016-oop_coffee_machine/commit/c24f41207fb15f39b0ad6501e1f3126d3bd9232e
diff --git a/docs/milestones/mil-002-core.md b/docs/milestones/mil-002-core.md
new file mode 100644
index 0000000..dfcfe6d
--- /dev/null
+++ b/docs/milestones/mil-002-core.md
@@ -0,0 +1,77 @@
+# Phase 2: Coffee Machine Program
+
+## Metadata
+| Key | Value |
+| --- | --- |
+| ID | MIL-002 |
+| CrossReference | [BC-001], [SA-001], [PP-001] |
+| Language | en |
+| Domain | it |
+
+## Version History
+| Date | Status | Author | Reviewer | Change | Commit |
+| --- | --- | --- | --- | --- | --- |
+| 2026-10-07 | Deprecated | Jens Tirsvad Nielsen | S01 | Initial version | [c24f412] |
+| 2026-10-07 | Accepted | Jens Tirsvad Nielsen | S01 | Accepted after RC-004 (Go) | [c24f412] |
+
+---
+
+## Purpose
+
+Decide whether the coffee machine program works as the assignment describes and is covered by tests.
+
+## Deliverable
+
+Python modules `menu`, `coffee_maker`, `money_machine` and `main` under `src/coffee_machine/`, with Doxygen comments, plus pytest tests under `tests/`.
+
+## Go / No-Go Criteria
+
+| # | Criterion (objectively checkable) | Go | No-Go |
+| --- | --- | --- | --- |
+| 1 | `Menu.get_items` and `Menu.find_drink` exist and return the menu text and the matching drink or nothing | Met | Not met |
+| 2 | `CoffeeMaker.report`, `is_resource_sufficient` and `make_coffee` exist and behave as in the assignment | Met | Not met |
+| 3 | `MoneyMachine.report` and `make_payment` exist and behave as in the assignment | Met | Not met |
+| 4 | The main loop supports drink choice, `report` and `off` and checks resources before payment | Met | Not met |
+| 5 | `pytest` passes and constants come from `constants.py` only | Met | Not met |
+| 6 | Code review against `qc-programming-python` has a Go review record | Met | Not met |
+
+## Dependencies
+
+| Depends on | Reason |
+| --- | --- |
+| MIL-001 | Needs the skeleton, configuration and CI |
+
+## Traceability
+
+| Business Case objective / KPI / user story | Reference |
+| --- | --- |
+| Objectives 1 and 2; success criteria 1 and 4 | [BC-001] |
+
+## Ownership
+
+| Role | Stakeholder ID (SA) |
+| --- | --- |
+| Owner | S01 |
+| Approving reviewer | S01 |
+
+## Target Date
+
+2026-10-14 — after Phase 1.
+
+## Tasks
+
+| # | Task | Summary | Needs its own Use Case/User Story? | Reference |
+| --- | --- | --- | --- | --- |
+| 1 | Implement Menu and MenuItem | Create `MenuItem` (name, cost, ingredients) and `Menu` with `get_items` (drink names for the prompt) and `find_drink` (returns the item or None for an unknown name), reading data from `constants.py`. | No | |
+| 2 | Implement CoffeeMaker | Create `CoffeeMaker` holding the resources, with `report`, `is_resource_sufficient` (prints which ingredient is short) and `make_coffee` (deducts ingredients). | No | |
+| 3 | Implement MoneyMachine | Create `MoneyMachine` with `report` (profit), and `make_payment` that processes coins, gives change, adds profit and refunds when money is insufficient. | No | |
+| 4 | Implement main loop | Create the entry point that keeps the machine running, accepts a drink name, `report` and `off`, and checks resources before taking payment before making coffee. The course supplies the design, so no separate use case is modelled (see PP-001 Open Issues). | No | |
+| 5 | Write pytest tests | Test each class and the main loop (with patched `input`) for sufficient and insufficient resources, exact, excess and short payment, unknown drink, report and off. | No | |
+| 6 | Review code against qc-programming-python | Review `src/` and `tests/` against the Python checklist and record the result as an RC before the pull request. | No | |
+
+---
+
+[BC-001]: ../business-case.md
+[SA-001]: ../stakeholder-analysis.md
+[PP-001]: ../project-plan.md
+[c24f412]: https://git.tirsystem.com/Tirsvad-Udemy-100_days_of_code/016-oop_coffee_machine/commit/c24f41207fb15f39b0ad6501e1f3126d3bd9232e
diff --git a/docs/milestones/mil-003-docs.md b/docs/milestones/mil-003-docs.md
new file mode 100644
index 0000000..06a556a
--- /dev/null
+++ b/docs/milestones/mil-003-docs.md
@@ -0,0 +1,74 @@
+# Phase 3: Documentation and Publication
+
+## Metadata
+| Key | Value |
+| --- | --- |
+| ID | MIL-003 |
+| CrossReference | [BC-001], [SA-001], [PP-001] |
+| Language | en |
+| Domain | it |
+
+## Version History
+| Date | Status | Author | Reviewer | Change | Commit |
+| --- | --- | --- | --- | --- | --- |
+| 2026-10-07 | Deprecated | Jens Tirsvad Nielsen | S01 | Initial version | [c24f412] |
+| 2026-10-07 | Accepted | Jens Tirsvad Nielsen | S01 | Accepted after RC-005 (Go) | [c24f412] |
+
+---
+
+## Purpose
+
+Decide whether the repository is documented and presentable for S02 and S03.
+
+## Deliverable
+
+README following the course template, generated Doxygen documentation steps, and a repository description and topics on the git host.
+
+## Go / No-Go Criteria
+
+| # | Criterion (objectively checkable) | Go | No-Go |
+| --- | --- | --- | --- |
+| 1 | README has all template sections and the Windows, Debian and macOS venv steps including `python -m pip install --upgrade pip` | Met | Not met |
+| 2 | Following the README on a clean clone runs the program and the tests | Met | Not met |
+| 3 | `doxygen Doxyfile` produces documentation from the source comments | Met | Not met |
+| 4 | Repository description and at least 3 topics are set on the git host | Met | Not met |
+| 5 | README and LICENSE agree on the licence | Met | Not met |
+
+## Dependencies
+
+| Depends on | Reason |
+| --- | --- |
+| MIL-002 | Documents the finished program |
+
+## Traceability
+
+| Business Case objective / KPI / user story | Reference |
+| --- | --- |
+| Objectives 3 and 4; success criteria 3 and 5 | [BC-001] |
+
+## Ownership
+
+| Role | Stakeholder ID (SA) |
+| --- | --- |
+| Owner | S01 |
+| Approving reviewer | S01 |
+
+## Target Date
+
+2026-10-16 — after Phase 2.
+
+## Tasks
+
+| # | Task | Summary | Needs its own Use Case/User Story? | Reference |
+| --- | --- | --- | --- | --- |
+| 1 | Write README | Write `README.md` from the course template: requirements, set-up for Windows PowerShell, Debian and macOS using a local `.venv` and `python -m pip install --upgrade pip`, run, test, CI, Doxygen build, project layout and licence. | No | |
+| 2 | Verify Doxygen build | Run Doxygen on a clean clone and check that classes and methods from the Doxygen comments appear in the output. | No | |
+| 3 | Set repository description and topics | Set a short description and topics on the git host repository (`Tirsvad-Udemy-100_days_of_code`) through its API using the token from `.env`, which stays personal and is never read by the project code. Needs the Product Owner's go-ahead because it changes the remote. | No | |
+| 4 | Verify setup from a clean clone | Follow the README from a fresh clone on the Product Owner's machine and fix any step that does not work. | No | |
+
+---
+
+[BC-001]: ../business-case.md
+[SA-001]: ../stakeholder-analysis.md
+[PP-001]: ../project-plan.md
+[c24f412]: https://git.tirsystem.com/Tirsvad-Udemy-100_days_of_code/016-oop_coffee_machine/commit/c24f41207fb15f39b0ad6501e1f3126d3bd9232e
diff --git a/docs/project-plan.md b/docs/project-plan.md
new file mode 100644
index 0000000..9f13c04
--- /dev/null
+++ b/docs/project-plan.md
@@ -0,0 +1,85 @@
+# Project Plan: OOP Coffee Machine
+
+## Metadata
+| Key | Value |
+| --- | --- |
+| ID | PP-001 |
+| CrossReference | [BC-001], [SA-001], [MIL-001], [MIL-002], [MIL-003] |
+| Language | en |
+| Domain | it |
+
+## Version History
+| Date | Status | Author | Reviewer | Change | Commit |
+| --- | --- | --- | --- | --- | --- |
+| 2026-10-07 | Deprecated | Jens Tirsvad Nielsen | S01 | Initial version | [c24f412] |
+| 2026-10-07 | Accepted | Jens Tirsvad Nielsen | S01 | Accepted after RC-006 (Go) | [c24f412] |
+
+---
+
+## Purpose
+
+Schedules the three phases that deliver the coffee machine repository, as
+required by [BC-001], with the communication cadence of [SA-001].
+
+## Planning Assumptions
+
+- Start date 2026-10-07; one phase per week or less, each ending in a pull request.
+- S01 is owner and reviewer of every phase; S02 and S03 are informed through the README.
+- Nothing under `src/` or `tests/` is written until the milestones are `Accepted` with a `Go` review.
+
+## Gateway Schedule
+
+| Gateway | Document | Window | Decision date | Owner | Stories | Main deliverable | Milestone |
+| --- | --- | --- | --- | --- | --- | --- | --- |
+| Phase 1: Project Setup | [MIL-001] | 2026-10-07 to 2026-10-09 | 2026-10-09 | S01 | None | Skeleton, `pyproject.toml`, Doxyfile, CI | |
+| Phase 2: Coffee Machine Program | [MIL-002] | 2026-10-10 to 2026-10-14 | 2026-10-14 | S01 | None | Menu, CoffeeMaker, MoneyMachine, main loop, tests | |
+| Phase 3: Documentation and Publication | [MIL-003] | 2026-10-15 to 2026-10-16 | 2026-10-16 | S01 | None | README, Doxygen docs, repository description and topics | |
+
+## Timeline diagram
+
+```plantuml
+@startgantt
+Project starts 2026-10-07
+[Phase 1: Project Setup] starts 2026-10-07 and ends 2026-10-09
+[Phase 2: Coffee Machine Program] starts 2026-10-10 and ends 2026-10-14
+[Phase 3: Documentation and Publication] starts 2026-10-15 and ends 2026-10-16
+[Phase 1: Project Setup] -> [Phase 2: Coffee Machine Program]
+[Phase 2: Coffee Machine Program] -> [Phase 3: Documentation and Publication]
+@endgantt
+```
+
+## Scope Coverage
+
+| Business Case scope item | Gateway |
+| --- | --- |
+| Package, tests, `pyproject.toml`, `.gitignore`, `constants.py`, Doxyfile | [MIL-001] |
+| Coffee machine program and tests | [MIL-002] |
+| README, Doxygen build | [MIL-003] |
+| Repository description and topics | [MIL-003] |
+
+## Dependencies
+
+[MIL-001] precedes [MIL-002], which precedes [MIL-003]. A No-Go on a phase moves every later date by the rework time.
+
+## Plan Risks
+
+| Risk | Impact | Mitigation |
+| --- | --- | --- |
+| Review of each document delays the next phase | Medium | S01 reviews in the same session as the draft |
+| The git host token cannot set topics through the API | Low | Set the description and topics by hand in the web UI |
+
+## Open Issues
+
+- Dates are proposals; S01 confirms or changes them.
+- Tasks are all plain tasks: the course supplies the design, so no use case or user story is modelled. S01 may ask for a use case "User orders a drink".
+- `PP` has no QC checklist yet; the plan is validated against the Go / No-Go criteria of each milestone.
+- Which remote receives the repository description and topics (`git.tirsystem.com`, GitHub mirror, or both) is for S01 to confirm; both remotes exist.
+
+---
+
+[BC-001]: ./business-case.md
+[SA-001]: ./stakeholder-analysis.md
+[MIL-001]: ./milestones/mil-001-setup.md
+[MIL-002]: ./milestones/mil-002-core.md
+[MIL-003]: ./milestones/mil-003-docs.md
+[c24f412]: https://git.tirsystem.com/Tirsvad-Udemy-100_days_of_code/016-oop_coffee_machine/commit/c24f41207fb15f39b0ad6501e1f3126d3bd9232e
diff --git a/docs/sqa/reviews/rc-001-business-case.md b/docs/sqa/reviews/rc-001-business-case.md
new file mode 100644
index 0000000..e740e2f
--- /dev/null
+++ b/docs/sqa/reviews/rc-001-business-case.md
@@ -0,0 +1,69 @@
+# Review: Business Case BC-001
+
+## Metadata
+| Key | Value |
+| --- | --- |
+| ID | RC-001 |
+| CrossReference | [BC-001], [QC-BC-001], [QC-LANG-001] |
+
+## Version History
+| Date | Status | Author | Reviewer | Change | Commit |
+| --- | --- | --- | --- | --- | --- |
+| 2026-10-07 | Accepted | Jens Tirsvad Nielsen | S01 | Review record | [c24f412] |
+
+---
+
+## Artifact Under Review
+
+- Instance reviewed: [BC-001]
+- Checklist used: [QC-BC-001]
+- Scope: full review
+- Language and domain: en / it
+- Language reviewer: none
+
+## Checklist Results
+
+| # | Criterion | Status | Evidence/Notes |
+| --- | --- | --- | --- |
+| 1 | ROI/Cost-Benefit analysis is quantitative, or where qualitative, is explicitly justified | Pass | Cost-Benefit Assessment now states it is qualitative because there is no revenue or budget to quantify (fixed during this review). |
+| 2 | Risks are identified with documented impact and mitigation | Pass | Three risks, each with impact and mitigation. |
+| 3 | Success criteria are measurable, stating explicit targets rather than vague aspirations | Pass | Five criteria with targets and measures (pytest exit code 0, 0 dependencies, 3+ topics). |
+| 4 | Scope explicitly separates In Scope vs Out of Scope | Pass | `### In Scope` and `### Out of Scope` present. |
+| 5 | Stakeholders are cross-referenced to Stakeholder Analysis IDs rather than re-described inline | Pass | Stakeholders table uses S01, S02, S03 only. |
+| 6 | Methodology and quality-standard foundation are stated explicitly (e.g. ISO/IEC 25010, Larman) | Pass | ISO/IEC 25010:2023, the framework and the Python checklist are named. |
+| 7 | Assumptions and constraints are explicit and clearly distinguished from one another | Pass | Separate sections; a target completion date was added to Constraints during this review. |
+| 8 | Document supports executive decision-making with a clear, unambiguous recommendation | Pass | "Proceed" with a one-sentence rationale. |
+
+## Language and Domain Results
+
+Checklist: [QC-LANG-001].
+
+| # | Criterion | Status | Evidence/Notes |
+| --- | --- | --- | --- |
+| 1 | The Metadata table has a `Language` row and a `Domain` row, and neither is a placeholder | Pass | `Language | en`, `Domain | it`. |
+| 2 | `Language` is a BCP 47 code and `Domain` is a value from the registry's domain list | Pass | `en` is BCP 47; `it` is in the registry's domain list. |
+| 3 | The content (prose and table cells) is written in the stated language | Pass | All prose and table cells are English. |
+| 4 | The register matches the one the registry gives for the artifact type | Pass | Register is IT Executive English as the registry states. |
+| 5 | Domain terms are the PO terms of the domain's dictionary, with no synonyms | Pass | No dictionary (`DICT`) exists yet; terms (Menu, CoffeeMaker, MoneyMachine, drink, resource) are the assignment's own and used consistently. |
+| 6 | Metadata keys, section headings, IDs and statuses are in English | Pass | Verified by reading the file. |
+| 7 | No translated twin (`..md`) exists beside the document | Pass | No twin file in `docs/`. |
+| 8 | A change of language or domain since the previous accepted version has a Version History row and was reviewed again | N-A | First accepted version; no language change. |
+| 9 | A reviewer competent in the domain, and in the language, has confirmed that the domain terms are used correctly | Pass | S01 reads English and works in the IT domain; S01 asked for this review and acceptance in chat. |
+| 10 | Abbreviations are spelled out on first use, in the stated language | Pass | PO, FURPS+, CI, PP, MIL are defined by the framework; PO is spelled out in the Stakeholder Analysis. |
+
+## Overall Verdict
+
+Go — all mandatory criteria pass. One defect (unjustified qualitative cost-benefit) and one gap (no schedule constraint for the milestones to check against) were fixed during the review.
+
+## Action Items
+
+| Action | Owner | Due |
+| --- | --- | --- |
+| Confirm the target date 2026-10-16 | S01 | 2026-10-09 |
+
+---
+
+[BC-001]: ../../business-case.md
+[QC-BC-001]: ../../../framework/qc/qc-business-case.md
+[QC-LANG-001]: ../../../framework/qc/qc-language-domain.md
+[c24f412]: https://git.tirsystem.com/Tirsvad-Udemy-100_days_of_code/016-oop_coffee_machine/commit/c24f41207fb15f39b0ad6501e1f3126d3bd9232e
diff --git a/docs/sqa/reviews/rc-002-stakeholder-analysis.md b/docs/sqa/reviews/rc-002-stakeholder-analysis.md
new file mode 100644
index 0000000..bdffc2f
--- /dev/null
+++ b/docs/sqa/reviews/rc-002-stakeholder-analysis.md
@@ -0,0 +1,69 @@
+# Review: Stakeholder Analysis SA-001
+
+## Metadata
+| Key | Value |
+| --- | --- |
+| ID | RC-002 |
+| CrossReference | [SA-001], [QC-SA-001], [QC-LANG-001] |
+
+## Version History
+| Date | Status | Author | Reviewer | Change | Commit |
+| --- | --- | --- | --- | --- | --- |
+| 2026-10-07 | Accepted | Jens Tirsvad Nielsen | S01 | Review record | [c24f412] |
+
+---
+
+## Artifact Under Review
+
+- Instance reviewed: [SA-001]
+- Checklist used: [QC-SA-001]
+- Scope: full review
+- Language and domain: en / it
+- Language reviewer: none
+
+## Checklist Results
+
+| # | Criterion | Status | Evidence/Notes |
+| --- | --- | --- | --- |
+| 1 | Power/Interest grid is filled for every stakeholder, with no gaps or unclassified entries | Pass | S01-S03 all have power, interest and quadrant. Levels for S02 and S03 are the drafter's classification, not given in the brief; S01 accepts them. |
+| 2 | Each stakeholder is assigned a unique, stable ID | Pass | S01, S02, S03. |
+| 3 | Roles and organizational context are defined with explicit Power and Interest levels, not just narrative description | Pass | Role, organization, HIGH/LOW levels in the table. |
+| 4 | Communication needs (channel, frequency, deliverable type) are mapped to project phases or milestones | Pass | Communication table maps to MIL-001 to MIL-003. |
+| 5 | Conflicting stakeholder interests are identified with documented mitigation or resolution strategies | Pass | One conflict (assignment names versus Python style) with a mitigation. |
+| 6 | Stakeholder concerns are explicitly traced to Business Case objectives | Pass | Business Goal Alignment table cites BC-001 objectives 1-4. |
+| 7 | Primary concerns are expressed in both business language and a recognized quality-attribute mapping (e.g. FURPS+) | Pass | FURPS+ mapping table. |
+| 8 | Document is understandable and navigable by non-technical stakeholders reviewing their own entry | Pass | Plain table, one row per stakeholder. |
+
+## Language and Domain Results
+
+Checklist: [QC-LANG-001].
+
+| # | Criterion | Status | Evidence/Notes |
+| --- | --- | --- | --- |
+| 1 | The Metadata table has a `Language` row and a `Domain` row, and neither is a placeholder | Pass | `Language | en`, `Domain | it`. |
+| 2 | `Language` is a BCP 47 code and `Domain` is a value from the registry's domain list | Pass | `en` is BCP 47; `it` is in the registry's domain list. |
+| 3 | The content (prose and table cells) is written in the stated language | Pass | All prose and table cells are English. |
+| 4 | The register matches the one the registry gives for the artifact type | Pass | Register is IT Professional English as the registry states. |
+| 5 | Domain terms are the PO terms of the domain's dictionary, with no synonyms | Pass | No dictionary (`DICT`) exists yet; terms (Menu, CoffeeMaker, MoneyMachine, drink, resource) are the assignment's own and used consistently. |
+| 6 | Metadata keys, section headings, IDs and statuses are in English | Pass | Verified by reading the file. |
+| 7 | No translated twin (`..md`) exists beside the document | Pass | No twin file in `docs/`. |
+| 8 | A change of language or domain since the previous accepted version has a Version History row and was reviewed again | N-A | First accepted version; no language change. |
+| 9 | A reviewer competent in the domain, and in the language, has confirmed that the domain terms are used correctly | Pass | S01 reads English and works in the IT domain; S01 asked for this review and acceptance in chat. |
+| 10 | Abbreviations are spelled out on first use, in the stated language | Pass | PO, FURPS+, CI, PP, MIL are defined by the framework; PO is spelled out in the Stakeholder Analysis. |
+
+## Overall Verdict
+
+Go — all criteria pass.
+
+## Action Items
+
+| Action | Owner | Due |
+| --- | --- | --- |
+| Confirm the Power/Interest levels of S02 and S03 | S01 | 2026-10-09 |
+
+---
+
+[SA-001]: ../../stakeholder-analysis.md
+[QC-SA-001]: ../../../framework/qc/qc-stakeholder-analysis.md
+[QC-LANG-001]: ../../../framework/qc/qc-language-domain.md
+[c24f412]: https://git.tirsystem.com/Tirsvad-Udemy-100_days_of_code/016-oop_coffee_machine/commit/c24f41207fb15f39b0ad6501e1f3126d3bd9232e
diff --git a/docs/sqa/reviews/rc-003-mil-001.md b/docs/sqa/reviews/rc-003-mil-001.md
new file mode 100644
index 0000000..60b6444
--- /dev/null
+++ b/docs/sqa/reviews/rc-003-mil-001.md
@@ -0,0 +1,67 @@
+# Review: Milestone MIL-001
+
+## Metadata
+| Key | Value |
+| --- | --- |
+| ID | RC-003 |
+| CrossReference | [MIL-001], [QC-MIL-001], [QC-LANG-001] |
+
+## Version History
+| Date | Status | Author | Reviewer | Change | Commit |
+| --- | --- | --- | --- | --- | --- |
+| 2026-10-07 | Accepted | Jens Tirsvad Nielsen | S01 | Review record | [c24f412] |
+
+---
+
+## Artifact Under Review
+
+- Instance reviewed: [MIL-001]
+- Checklist used: [QC-MIL-001]
+- Scope: full review
+- Language and domain: en / it
+- Language reviewer: none
+
+## Checklist Results
+
+| # | Criterion | Status | Evidence/Notes |
+| --- | --- | --- | --- |
+| 1 | A concrete deliverable is defined for every gate | Pass | Skeleton, `pyproject.toml`, Doxyfile and CI workflow. |
+| 2 | Explicit Go/No-Go criteria are stated for each gate | Pass | Criteria are checkable by a command or a file check (pytest, pip install, doxygen, `.gitignore`). |
+| 3 | Dependencies on other milestones are explicitly mapped | Pass | None (first phase), stated. |
+| 4 | Each milestone is traceable to a Business Case objective or KPI | Pass | Objectives 2 and 3, success criteria 1 and 2. |
+| 5 | Milestone owner and approving reviewer are identified | Pass | Owner and approving reviewer are S01. Same person; accepted for a solo project (see Action Items). |
+| 6 | Milestone has a defined target date consistent with project constraints | Pass | 2026-10-09, on or before the BC-001 completion constraint 2026-10-16. |
+
+## Language and Domain Results
+
+Checklist: [QC-LANG-001].
+
+| # | Criterion | Status | Evidence/Notes |
+| --- | --- | --- | --- |
+| 1 | The Metadata table has a `Language` row and a `Domain` row, and neither is a placeholder | Pass | `Language | en`, `Domain | it`. |
+| 2 | `Language` is a BCP 47 code and `Domain` is a value from the registry's domain list | Pass | `en` is BCP 47; `it` is in the registry's domain list. |
+| 3 | The content (prose and table cells) is written in the stated language | Pass | All prose and table cells are English. |
+| 4 | The register matches the one the registry gives for the artifact type | Pass | Register is IT Executive English as the registry states. |
+| 5 | Domain terms are the PO terms of the domain's dictionary, with no synonyms | Pass | No dictionary (`DICT`) exists yet; terms (Menu, CoffeeMaker, MoneyMachine, drink, resource) are the assignment's own and used consistently. |
+| 6 | Metadata keys, section headings, IDs and statuses are in English | Pass | Verified by reading the file. |
+| 7 | No translated twin (`..md`) exists beside the document | Pass | No twin file in `docs/`. |
+| 8 | A change of language or domain since the previous accepted version has a Version History row and was reviewed again | N-A | First accepted version; no language change. |
+| 9 | A reviewer competent in the domain, and in the language, has confirmed that the domain terms are used correctly | Pass | S01 reads English and works in the IT domain; S01 asked for this review and acceptance in chat. |
+| 10 | Abbreviations are spelled out on first use, in the stated language | Pass | PO, FURPS+, CI, PP, MIL are defined by the framework; PO is spelled out in the Stakeholder Analysis. |
+
+## Overall Verdict
+
+Go — all criteria pass.
+
+## Action Items
+
+| Action | Owner | Due |
+| --- | --- | --- |
+| Confirm that S01 as both owner and approving reviewer is acceptable | S01 | 2026-10-09 |
+
+---
+
+[MIL-001]: ../../milestones/mil-001-setup.md
+[QC-MIL-001]: ../../../framework/qc/qc-milestones-gateways.md
+[QC-LANG-001]: ../../../framework/qc/qc-language-domain.md
+[c24f412]: https://git.tirsystem.com/Tirsvad-Udemy-100_days_of_code/016-oop_coffee_machine/commit/c24f41207fb15f39b0ad6501e1f3126d3bd9232e
diff --git a/docs/sqa/reviews/rc-004-mil-002.md b/docs/sqa/reviews/rc-004-mil-002.md
new file mode 100644
index 0000000..d46d13b
--- /dev/null
+++ b/docs/sqa/reviews/rc-004-mil-002.md
@@ -0,0 +1,67 @@
+# Review: Milestone MIL-002
+
+## Metadata
+| Key | Value |
+| --- | --- |
+| ID | RC-004 |
+| CrossReference | [MIL-002], [QC-MIL-001], [QC-LANG-001] |
+
+## Version History
+| Date | Status | Author | Reviewer | Change | Commit |
+| --- | --- | --- | --- | --- | --- |
+| 2026-10-07 | Accepted | Jens Tirsvad Nielsen | S01 | Review record | [c24f412] |
+
+---
+
+## Artifact Under Review
+
+- Instance reviewed: [MIL-002]
+- Checklist used: [QC-MIL-001]
+- Scope: full review
+- Language and domain: en / it
+- Language reviewer: none
+
+## Checklist Results
+
+| # | Criterion | Status | Evidence/Notes |
+| --- | --- | --- | --- |
+| 1 | A concrete deliverable is defined for every gate | Pass | The four modules and the tests. |
+| 2 | Explicit Go/No-Go criteria are stated for each gate | Pass | Criteria are checkable by a command or a file check (pytest, pip install, doxygen, `.gitignore`). |
+| 3 | Dependencies on other milestones are explicitly mapped | Pass | Depends on MIL-001, with reason. |
+| 4 | Each milestone is traceable to a Business Case objective or KPI | Pass | Objectives 1 and 2, success criteria 1 and 4. |
+| 5 | Milestone owner and approving reviewer are identified | Pass | Owner and approving reviewer are S01. Same person; accepted for a solo project (see Action Items). |
+| 6 | Milestone has a defined target date consistent with project constraints | Pass | 2026-10-14, on or before the BC-001 completion constraint 2026-10-16. |
+
+## Language and Domain Results
+
+Checklist: [QC-LANG-001].
+
+| # | Criterion | Status | Evidence/Notes |
+| --- | --- | --- | --- |
+| 1 | The Metadata table has a `Language` row and a `Domain` row, and neither is a placeholder | Pass | `Language | en`, `Domain | it`. |
+| 2 | `Language` is a BCP 47 code and `Domain` is a value from the registry's domain list | Pass | `en` is BCP 47; `it` is in the registry's domain list. |
+| 3 | The content (prose and table cells) is written in the stated language | Pass | All prose and table cells are English. |
+| 4 | The register matches the one the registry gives for the artifact type | Pass | Register is IT Executive English as the registry states. |
+| 5 | Domain terms are the PO terms of the domain's dictionary, with no synonyms | Pass | No dictionary (`DICT`) exists yet; terms (Menu, CoffeeMaker, MoneyMachine, drink, resource) are the assignment's own and used consistently. |
+| 6 | Metadata keys, section headings, IDs and statuses are in English | Pass | Verified by reading the file. |
+| 7 | No translated twin (`..md`) exists beside the document | Pass | No twin file in `docs/`. |
+| 8 | A change of language or domain since the previous accepted version has a Version History row and was reviewed again | N-A | First accepted version; no language change. |
+| 9 | A reviewer competent in the domain, and in the language, has confirmed that the domain terms are used correctly | Pass | S01 reads English and works in the IT domain; S01 asked for this review and acceptance in chat. |
+| 10 | Abbreviations are spelled out on first use, in the stated language | Pass | PO, FURPS+, CI, PP, MIL are defined by the framework; PO is spelled out in the Stakeholder Analysis. |
+
+## Overall Verdict
+
+Go — all criteria pass.
+
+## Action Items
+
+| Action | Owner | Due |
+| --- | --- | --- |
+| Confirm that S01 as both owner and approving reviewer is acceptable | S01 | 2026-10-09 |
+
+---
+
+[MIL-002]: ../../milestones/mil-002-core.md
+[QC-MIL-001]: ../../../framework/qc/qc-milestones-gateways.md
+[QC-LANG-001]: ../../../framework/qc/qc-language-domain.md
+[c24f412]: https://git.tirsystem.com/Tirsvad-Udemy-100_days_of_code/016-oop_coffee_machine/commit/c24f41207fb15f39b0ad6501e1f3126d3bd9232e
diff --git a/docs/sqa/reviews/rc-005-mil-003.md b/docs/sqa/reviews/rc-005-mil-003.md
new file mode 100644
index 0000000..02affd3
--- /dev/null
+++ b/docs/sqa/reviews/rc-005-mil-003.md
@@ -0,0 +1,67 @@
+# Review: Milestone MIL-003
+
+## Metadata
+| Key | Value |
+| --- | --- |
+| ID | RC-005 |
+| CrossReference | [MIL-003], [QC-MIL-001], [QC-LANG-001] |
+
+## Version History
+| Date | Status | Author | Reviewer | Change | Commit |
+| --- | --- | --- | --- | --- | --- |
+| 2026-10-07 | Accepted | Jens Tirsvad Nielsen | S01 | Review record | [c24f412] |
+
+---
+
+## Artifact Under Review
+
+- Instance reviewed: [MIL-003]
+- Checklist used: [QC-MIL-001]
+- Scope: full review
+- Language and domain: en / it
+- Language reviewer: none
+
+## Checklist Results
+
+| # | Criterion | Status | Evidence/Notes |
+| --- | --- | --- | --- |
+| 1 | A concrete deliverable is defined for every gate | Pass | README, Doxygen docs, repository description and topics. |
+| 2 | Explicit Go/No-Go criteria are stated for each gate | Pass | Criteria are checkable by a command or a file check (pytest, pip install, doxygen, `.gitignore`). |
+| 3 | Dependencies on other milestones are explicitly mapped | Pass | Depends on MIL-002, with reason. |
+| 4 | Each milestone is traceable to a Business Case objective or KPI | Pass | Objectives 3 and 4, success criteria 3 and 5. |
+| 5 | Milestone owner and approving reviewer are identified | Pass | Owner and approving reviewer are S01. Same person; accepted for a solo project (see Action Items). |
+| 6 | Milestone has a defined target date consistent with project constraints | Pass | 2026-10-16, on or before the BC-001 completion constraint 2026-10-16. |
+
+## Language and Domain Results
+
+Checklist: [QC-LANG-001].
+
+| # | Criterion | Status | Evidence/Notes |
+| --- | --- | --- | --- |
+| 1 | The Metadata table has a `Language` row and a `Domain` row, and neither is a placeholder | Pass | `Language | en`, `Domain | it`. |
+| 2 | `Language` is a BCP 47 code and `Domain` is a value from the registry's domain list | Pass | `en` is BCP 47; `it` is in the registry's domain list. |
+| 3 | The content (prose and table cells) is written in the stated language | Pass | All prose and table cells are English. |
+| 4 | The register matches the one the registry gives for the artifact type | Pass | Register is IT Executive English as the registry states. |
+| 5 | Domain terms are the PO terms of the domain's dictionary, with no synonyms | Pass | No dictionary (`DICT`) exists yet; terms (Menu, CoffeeMaker, MoneyMachine, drink, resource) are the assignment's own and used consistently. |
+| 6 | Metadata keys, section headings, IDs and statuses are in English | Pass | Verified by reading the file. |
+| 7 | No translated twin (`..md`) exists beside the document | Pass | No twin file in `docs/`. |
+| 8 | A change of language or domain since the previous accepted version has a Version History row and was reviewed again | N-A | First accepted version; no language change. |
+| 9 | A reviewer competent in the domain, and in the language, has confirmed that the domain terms are used correctly | Pass | S01 reads English and works in the IT domain; S01 asked for this review and acceptance in chat. |
+| 10 | Abbreviations are spelled out on first use, in the stated language | Pass | PO, FURPS+, CI, PP, MIL are defined by the framework; PO is spelled out in the Stakeholder Analysis. |
+
+## Overall Verdict
+
+Go — all criteria pass.
+
+## Action Items
+
+| Action | Owner | Due |
+| --- | --- | --- |
+| Confirm that S01 as both owner and approving reviewer is acceptable | S01 | 2026-10-09 |
+
+---
+
+[MIL-003]: ../../milestones/mil-003-docs.md
+[QC-MIL-001]: ../../../framework/qc/qc-milestones-gateways.md
+[QC-LANG-001]: ../../../framework/qc/qc-language-domain.md
+[c24f412]: https://git.tirsystem.com/Tirsvad-Udemy-100_days_of_code/016-oop_coffee_machine/commit/c24f41207fb15f39b0ad6501e1f3126d3bd9232e
diff --git a/docs/sqa/reviews/rc-006-project-plan.md b/docs/sqa/reviews/rc-006-project-plan.md
new file mode 100644
index 0000000..4f61e01
--- /dev/null
+++ b/docs/sqa/reviews/rc-006-project-plan.md
@@ -0,0 +1,63 @@
+# Review: Project Plan PP-001
+
+## Metadata
+| Key | Value |
+| --- | --- |
+| ID | RC-006 |
+| CrossReference | [PP-001], [QC-LANG-001] |
+
+## Version History
+| Date | Status | Author | Reviewer | Change | Commit |
+| --- | --- | --- | --- | --- | --- |
+| 2026-10-07 | Accepted | Jens Tirsvad Nielsen | S01 | Review record | [c24f412] |
+
+---
+
+## Artifact Under Review
+
+- Instance reviewed: [PP-001]
+- Checklist used: none (PP has no QC checklist; see the first row of Checklist Results)
+- Scope: full review
+- Language and domain: en / it
+- Language reviewer: none
+
+## Checklist Results
+
+| # | Criterion | Status | Evidence/Notes |
+| --- | --- | --- | --- |
+| 1 | Plan schedules every phase against the Business Case constraint (no QC checklist exists for PP; validated against BC-001 and the Go/No-Go criteria of each MIL) | Pass | Three phases end on or before 2026-10-16; each MIL target date equals the plan's decision date. |
+| 2 | Every required PP section is present, in order | Pass | Purpose through Open Issues are present. |
+| 3 | Gateway Schedule lists every MIL document | Pass | MIL-001, MIL-002, MIL-003. |
+
+## Language and Domain Results
+
+Checklist: [QC-LANG-001].
+
+| # | Criterion | Status | Evidence/Notes |
+| --- | --- | --- | --- |
+| 1 | The Metadata table has a `Language` row and a `Domain` row, and neither is a placeholder | Pass | `Language | en`, `Domain | it`. |
+| 2 | `Language` is a BCP 47 code and `Domain` is a value from the registry's domain list | Pass | `en` is BCP 47; `it` is in the registry's domain list. |
+| 3 | The content (prose and table cells) is written in the stated language | Pass | All prose and table cells are English. |
+| 4 | The register matches the one the registry gives for the artifact type | Pass | Register is IT Executive English as the registry states. |
+| 5 | Domain terms are the PO terms of the domain's dictionary, with no synonyms | Pass | No dictionary (`DICT`) exists yet; terms (Menu, CoffeeMaker, MoneyMachine, drink, resource) are the assignment's own and used consistently. |
+| 6 | Metadata keys, section headings, IDs and statuses are in English | Pass | Verified by reading the file. |
+| 7 | No translated twin (`..md`) exists beside the document | Pass | No twin file in `docs/`. |
+| 8 | A change of language or domain since the previous accepted version has a Version History row and was reviewed again | N-A | First accepted version; no language change. |
+| 9 | A reviewer competent in the domain, and in the language, has confirmed that the domain terms are used correctly | Pass | S01 reads English and works in the IT domain; S01 asked for this review and acceptance in chat. |
+| 10 | Abbreviations are spelled out on first use, in the stated language | Pass | PO, FURPS+, CI, PP, MIL are defined by the framework; PO is spelled out in the Stakeholder Analysis. |
+
+## Overall Verdict
+
+Go — validated against the Business Case and the milestones; the plan is accepted by S01 as Product Owner.
+
+## Action Items
+
+| Action | Owner | Due |
+| --- | --- | --- |
+| Fill the `Milestone` column after `sync-project.sh --apply` | S01 | 2026-10-09 |
+
+---
+
+[PP-001]: ../../project-plan.md
+[QC-LANG-001]: ../../../framework/qc/qc-language-domain.md
+[c24f412]: https://git.tirsystem.com/Tirsvad-Udemy-100_days_of_code/016-oop_coffee_machine/commit/c24f41207fb15f39b0ad6501e1f3126d3bd9232e
diff --git a/docs/sqa/traceability-matrix.md b/docs/sqa/traceability-matrix.md
new file mode 100644
index 0000000..30469ff
--- /dev/null
+++ b/docs/sqa/traceability-matrix.md
@@ -0,0 +1,49 @@
+# Traceability Matrix
+
+## Metadata
+| Key | Value |
+| --- | --- |
+| ID | TM-001 |
+| CrossReference | [BC-001] |
+
+## Version History
+| Date | Status | Author | Reviewer | Change | Commit |
+| --- | --- | --- | --- | --- | --- |
+| 2026-10-07 | Proposed | Jens Tirsvad Nielsen | S01 | Initial version | [c24f412] |
+
+---
+
+## Purpose
+
+Tracks backward and forward links between artifact instances so that traceability is measurable. A row is added or updated whenever an artifact instance is created or reviewed.
+
+## Traceability Table
+
+| Artifact Instance | Type | Language | Domain | Upstream (Backward Link) | Downstream (Forward Link) | Last Reviewed (RC-ID) |
+| --- | --- | --- | --- | --- | --- | --- |
+| [BC-001] | Business Case | en | it | - | [SA-001], [PP-001] | [RC-001] |
+| [SA-001] | Stakeholder Analysis | en | it | [BC-001] | [PP-001] | [RC-002] |
+| [PP-001] | Project Plan | en | it | [BC-001], [SA-001] | [MIL-001], [MIL-002], [MIL-003] | [RC-006] |
+| [MIL-001] | Milestone | en | it | [BC-001], [PP-001] | - | [RC-003] |
+| [MIL-002] | Milestone | en | it | [BC-001], [PP-001] | - | [RC-004] |
+| [MIL-003] | Milestone | en | it | [BC-001], [PP-001] | - | [RC-005] |
+
+## Coverage Notes
+
+No KPI, use case, user story or design artifact exists yet: the course supplies the design, so the tasks in the milestones are plain tasks. `-` in Upstream means foundational; in Downstream it means nothing is built on it yet.
+
+---
+
+[BC-001]: ../business-case.md
+[SA-001]: ../stakeholder-analysis.md
+[PP-001]: ../project-plan.md
+[MIL-001]: ../milestones/mil-001-setup.md
+[MIL-002]: ../milestones/mil-002-core.md
+[MIL-003]: ../milestones/mil-003-docs.md
+[RC-001]: reviews/rc-001-business-case.md
+[RC-002]: reviews/rc-002-stakeholder-analysis.md
+[RC-003]: reviews/rc-003-mil-001.md
+[RC-004]: reviews/rc-004-mil-002.md
+[RC-005]: reviews/rc-005-mil-003.md
+[RC-006]: reviews/rc-006-project-plan.md
+[c24f412]: https://git.tirsystem.com/Tirsvad-Udemy-100_days_of_code/016-oop_coffee_machine/commit/c24f41207fb15f39b0ad6501e1f3126d3bd9232e
diff --git a/docs/stakeholder-analysis.md b/docs/stakeholder-analysis.md
new file mode 100644
index 0000000..5e8474d
--- /dev/null
+++ b/docs/stakeholder-analysis.md
@@ -0,0 +1,83 @@
+# Stakeholder Analysis: OOP Coffee Machine
+
+## Metadata
+| Key | Value |
+| --- | --- |
+| ID | SA-001 |
+| CrossReference | [BC-001] |
+| Language | en |
+| Domain | it |
+
+## Version History
+| Date | Status | Author | Reviewer | Change | Commit |
+| --- | --- | --- | --- | --- | --- |
+| 2026-10-07 | Deprecated | Jens Tirsvad Nielsen | S01 | Initial version | [c24f412] |
+| 2026-10-07 | Accepted | Jens Tirsvad Nielsen | S01 | Accepted after RC-002 (Go) | [c24f412] |
+
+---
+
+## Purpose
+
+Identifies who is affected by the coffee machine repository and how closely
+each party is managed. Method: Mendelow's power/interest grid, with concerns
+mapped to FURPS+.
+
+## Stakeholder Summary Table
+
+| ID | Name | Role/Title | Organization | Power Level | Interest Level | Quadrant | Primary Concern (Business Language) |
+| --- | --- | --- | --- | --- | --- | --- | --- |
+| S01 | Jens Tirsvad Nielsen | Course participant; Product Owner, developer and reviewer | Tirsvad | HIGH | HIGH | Manage Closely | Finish the assignment with clean code, tests and documentation |
+| S02 | Udemy coursists | Fellow course participants | Udemy course community | LOW | HIGH | Keep Informed | Readable, runnable code with the assignment's function names, and README instructions to run it |
+| S03 | GitHub viewers | Repository browsers | Public | LOW | LOW | Monitor | A clear repository description, topics and README, and no runtime dependencies |
+
+## Power/Interest Classification Rationale
+
+- **Manage Closely (S01):** decides scope, writes and reviews everything.
+- **Keep Informed (S02):** cannot change the project but depends on its usability; the README is the channel.
+- **Monitor (S03):** casual visitors with no influence; the repository presentation is enough.
+
+## Primary Concerns and FURPS+ Mapping
+
+| ID | Concern | FURPS+ attribute |
+| --- | --- | --- |
+| S01 | Complete, tested assignment solution | Functionality, Reliability |
+| S01 | Traceable steps via pull requests | Supportability |
+| S02 | Assignment function names kept | Functionality |
+| S02 | Run instructions that work | Usability |
+| S03 | Clear description, topics and README | Usability |
+| S03 | No runtime dependencies | Implementation constraint, Supportability |
+
+## Communication Requirements
+
+| ID | Channel | Frequency | Deliverable | Phase / Milestone |
+| --- | --- | --- | --- | --- |
+| S01 | Chat and pull request review | Per phase | Working-tree changes and PRs | MIL-001, MIL-002, MIL-003 |
+| S02 | README | Once, updated on change | Setup, run and test instructions | MIL-003 |
+| S03 | Repository description, topics, README | Once | Repository presentation | MIL-003 |
+
+## Conflicting Interests and Mitigations
+
+| Conflict | Stakeholders | Mitigation |
+| --- | --- | --- |
+| S02 wants assignment names, while clean Python style prefers other names | S01, S02 | Keep the assignment's method names; follow the style rules elsewhere |
+
+## Traceability Analysis
+
+### Business Goal Alignment
+
+| Stakeholder | Concern | Business Case objective |
+| --- | --- | --- |
+| S01 | Complete, tested solution | [BC-001] objectives 1 and 2 |
+| S02 | Runnable instructions | [BC-001] objective 3 |
+| S03 | Presentable repository | [BC-001] objective 4 |
+
+## Sign-Off
+
+| Stakeholder ID | Decision | Date |
+| --- | --- | --- |
+| S01 | Pending review | |
+
+---
+
+[BC-001]: ./business-case.md
+[c24f412]: https://git.tirsystem.com/Tirsvad-Udemy-100_days_of_code/016-oop_coffee_machine/commit/c24f41207fb15f39b0ad6501e1f3126d3bd9232e
diff --git a/framework b/framework
new file mode 160000
index 0000000..ce1f9dd
--- /dev/null
+++ b/framework
@@ -0,0 +1 @@
+Subproject commit ce1f9ddd3c7a8d32ff30a50755fdc777f5a0c183
diff --git a/pyproject.toml b/pyproject.toml
new file mode 100644
index 0000000..63bc4e4
--- /dev/null
+++ b/pyproject.toml
@@ -0,0 +1,39 @@
+[build-system]
+requires = ["setuptools>=68"]
+build-backend = "setuptools.build_meta"
+
+[project]
+name = "coffee-machine"
+version = "0.1.0"
+description = "Object-oriented coffee machine program from Udemy's 100 Days of Code: The Complete Python Pro Bootcamp."
+readme = "README.md"
+requires-python = ">=3.13"
+license = { file = "LICENSE" }
+authors = [{ name = "Jens Tirsvad Nielsen" }]
+# No runtime dependencies on purpose (stakeholder S03).
+dependencies = []
+
+[project.optional-dependencies]
+dev = ["pytest>=8", "ruff>=0.6", "mypy>=1.11"]
+
+[project.scripts]
+coffee-machine = "coffee_machine.main:main"
+
+[tool.setuptools.packages.find]
+where = ["src"]
+
+[tool.pytest.ini_options]
+testpaths = ["tests"]
+pythonpath = ["src"]
+
+[tool.ruff]
+line-length = 88
+target-version = "py313"
+
+[tool.ruff.lint]
+select = ["E", "F", "I", "N", "UP", "B"]
+
+[tool.mypy]
+strict = true
+python_version = "3.13"
+files = ["src", "tests"]
diff --git a/src/coffee_machine/__init__.py b/src/coffee_machine/__init__.py
new file mode 100644
index 0000000..8a3636e
--- /dev/null
+++ b/src/coffee_machine/__init__.py
@@ -0,0 +1,3 @@
+"""! @file
+@brief Object-oriented coffee machine from the 100 Days of Code course.
+"""
diff --git a/src/coffee_machine/constants.py b/src/coffee_machine/constants.py
new file mode 100644
index 0000000..b6408a0
--- /dev/null
+++ b/src/coffee_machine/constants.py
@@ -0,0 +1,45 @@
+"""! @file
+@brief Constants for the coffee machine: menu, resources, coins and commands.
+"""
+
+from typing import Final
+
+## @name Ingredient names
+## @{
+WATER: Final = "water"
+MILK: Final = "milk"
+COFFEE: Final = "coffee"
+## @}
+
+## @brief Cost in dollars and ingredient amounts per drink.
+MENU: Final[dict[str, dict[str, object]]] = {
+ "espresso": {"cost": 1.5, "ingredients": {WATER: 50, MILK: 0, COFFEE: 18}},
+ "latte": {"cost": 2.5, "ingredients": {WATER: 200, MILK: 150, COFFEE: 24}},
+ "cappuccino": {"cost": 3.0, "ingredients": {WATER: 250, MILK: 100, COFFEE: 24}},
+}
+
+## @brief Amount of each ingredient the machine starts with.
+INITIAL_RESOURCES: Final[dict[str, int]] = {WATER: 300, MILK: 200, COFFEE: 100}
+
+## @brief Units used when reporting each resource.
+RESOURCE_UNITS: Final[dict[str, str]] = {WATER: "ml", MILK: "ml", COFFEE: "g"}
+
+## @brief Value in dollars of each accepted coin.
+COIN_VALUES: Final[dict[str, float]] = {
+ "quarters": 0.25,
+ "dimes": 0.10,
+ "nickels": 0.05,
+ "pennies": 0.01,
+}
+
+## @brief Money in the machine at the start.
+INITIAL_PROFIT: Final = 0.0
+
+## @brief Currency symbol shown in messages.
+CURRENCY: Final = "$"
+
+## @name Commands at the prompt
+## @{
+COMMAND_OFF: Final = "off"
+COMMAND_REPORT: Final = "report"
+## @}
diff --git a/tests/test_constants.py b/tests/test_constants.py
new file mode 100644
index 0000000..b6e46ca
--- /dev/null
+++ b/tests/test_constants.py
@@ -0,0 +1,20 @@
+"""! @file
+@brief Checks that the constants are consistent with each other.
+"""
+
+from coffee_machine import constants
+
+
+def test_every_drink_uses_known_ingredients() -> None:
+ known = set(constants.INITIAL_RESOURCES)
+ for drink in constants.MENU.values():
+ assert set(drink["ingredients"]) <= known # type: ignore[call-overload]
+
+
+def test_every_resource_has_a_unit() -> None:
+ assert set(constants.INITIAL_RESOURCES) == set(constants.RESOURCE_UNITS)
+
+
+def test_commands_are_not_drink_names() -> None:
+ assert constants.COMMAND_OFF not in constants.MENU
+ assert constants.COMMAND_REPORT not in constants.MENU