From 5ebc1df94a4bf8fefe16db074d71f46bcb13abc4 Mon Sep 17 00:00:00 2001 From: Jens Tirsvad Nielsen Date: Fri, 6 Nov 2026 12:21:57 +0800 Subject: [PATCH 1/2] Set up the project skeleton, tooling and documentation Adds pyproject.toml, .gitignore, constants.py, the layer packages, a smoke test, the Doxyfile and the README with venv, run and test instructions. Task: MIL-001#1 Task: MIL-001#2 Task: MIL-001#3 Task: MIL-001#4 Task: MIL-001#5 Task: MIL-001#6 --- .gitignore | 33 ++ Doxyfile | 423 ++++++++++++++++++++ README.md | 120 +++++- docs/artifact-registry.md | 2 +- docs/sqa/reviews/rc-008-code-mil-001.md | 61 +++ pyproject.toml | 42 ++ src/higher_lower/__init__.py | 4 + src/higher_lower/application/__init__.py | 4 + src/higher_lower/constants.py | 45 +++ src/higher_lower/domain/__init__.py | 4 + src/higher_lower/infrastructure/__init__.py | 4 + src/higher_lower/presentation/__init__.py | 4 + tests/unit/test_constants.py | 21 + 13 files changed, 765 insertions(+), 2 deletions(-) create mode 100644 .gitignore create mode 100644 Doxyfile create mode 100644 docs/sqa/reviews/rc-008-code-mil-001.md create mode 100644 pyproject.toml create mode 100644 src/higher_lower/__init__.py create mode 100644 src/higher_lower/application/__init__.py create mode 100644 src/higher_lower/constants.py create mode 100644 src/higher_lower/domain/__init__.py create mode 100644 src/higher_lower/infrastructure/__init__.py create mode 100644 src/higher_lower/presentation/__init__.py create mode 100644 tests/unit/test_constants.py diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..1469e46 --- /dev/null +++ b/.gitignore @@ -0,0 +1,33 @@ +# Python +__pycache__/ +*.py[cod] +*.egg-info/ +build/ +dist/ +.pytest_cache/ +.mypy_cache/ +.ruff_cache/ +.coverage +htmlcov/ + +# Virtual environments +.venv/ +venv/ +env/ + +# Secrets and personal files (tokens stay in .env, the project never imports it) +.env +.env.* +!.env.example + +# Generated documentation +/build/ + +# AI prompt log: this repository is public +/docs/ai-prompts/ + +# Editors and OS +.idea/ +.vscode/ +.DS_Store +Thumbs.db diff --git a/Doxyfile b/Doxyfile new file mode 100644 index 0000000..60f72c3 --- /dev/null +++ b/Doxyfile @@ -0,0 +1,423 @@ +# Doxyfile 1.15.0 + +#--------------------------------------------------------------------------- +# Project related configuration options +#--------------------------------------------------------------------------- +DOXYFILE_ENCODING = UTF-8 +PROJECT_NAME = "Higher or Lower" +PROJECT_NUMBER = +PROJECT_BRIEF = "Day 55 of 100 Days of Code: a Flask guessing game" +PROJECT_LOGO = +PROJECT_ICON = +OUTPUT_DIRECTORY = build +CREATE_SUBDIRS = NO +CREATE_SUBDIRS_LEVEL = 8 +ALLOW_UNICODE_NAMES = NO +OUTPUT_LANGUAGE = English +BRIEF_MEMBER_DESC = YES +REPEAT_BRIEF = YES +ABBREVIATE_BRIEF = "The $name class" \ + "The $name widget" \ + "The $name file" \ + is \ + provides \ + specifies \ + contains \ + represents \ + a \ + an \ + the +ALWAYS_DETAILED_SEC = NO +INLINE_INHERITED_MEMB = NO +FULL_PATH_NAMES = YES +STRIP_FROM_PATH = +STRIP_FROM_INC_PATH = +SHORT_NAMES = NO +JAVADOC_AUTOBRIEF = NO +JAVADOC_BANNER = NO +QT_AUTOBRIEF = NO +MULTILINE_CPP_IS_BRIEF = NO +PYTHON_DOCSTRING = YES +INHERIT_DOCS = YES +SEPARATE_MEMBER_PAGES = NO +TAB_SIZE = 4 +ALIASES = +OPTIMIZE_OUTPUT_FOR_C = NO +OPTIMIZE_OUTPUT_JAVA = YES +OPTIMIZE_FOR_FORTRAN = NO +OPTIMIZE_OUTPUT_VHDL = NO +OPTIMIZE_OUTPUT_SLICE = NO +EXTENSION_MAPPING = +MARKDOWN_SUPPORT = YES +MARKDOWN_STRICT = YES +TOC_INCLUDE_HEADINGS = 6 +MARKDOWN_ID_STYLE = DOXYGEN +AUTOLINK_SUPPORT = YES +AUTOLINK_IGNORE_WORDS = +BUILTIN_STL_SUPPORT = NO +CPP_CLI_SUPPORT = NO +SIP_SUPPORT = NO +IDL_PROPERTY_SUPPORT = YES +DISTRIBUTE_GROUP_DOC = NO +GROUP_NESTED_COMPOUNDS = NO +SUBGROUPING = YES +INLINE_GROUPED_CLASSES = NO +INLINE_SIMPLE_STRUCTS = NO +TYPEDEF_HIDES_STRUCT = NO +LOOKUP_CACHE_SIZE = 0 +NUM_PROC_THREADS = 1 +TIMESTAMP = NO +#--------------------------------------------------------------------------- +# Build related configuration options +#--------------------------------------------------------------------------- +EXTRACT_ALL = YES +EXTRACT_PRIVATE = NO +EXTRACT_PRIV_VIRTUAL = NO +EXTRACT_PACKAGE = NO +EXTRACT_STATIC = NO +EXTRACT_LOCAL_CLASSES = YES +EXTRACT_LOCAL_METHODS = NO +EXTRACT_ANON_NSPACES = NO +RESOLVE_UNNAMED_PARAMS = YES +HIDE_UNDOC_MEMBERS = NO +HIDE_UNDOC_CLASSES = NO +HIDE_UNDOC_NAMESPACES = YES +HIDE_FRIEND_COMPOUNDS = NO +HIDE_IN_BODY_DOCS = NO +INTERNAL_DOCS = NO +CASE_SENSE_NAMES = SYSTEM +HIDE_SCOPE_NAMES = NO +HIDE_COMPOUND_REFERENCE= NO +SHOW_HEADERFILE = YES +SHOW_INCLUDE_FILES = YES +SHOW_GROUPED_MEMB_INC = NO +FORCE_LOCAL_INCLUDES = NO +INLINE_INFO = YES +SORT_MEMBER_DOCS = YES +SORT_BRIEF_DOCS = NO +SORT_MEMBERS_CTORS_1ST = NO +SORT_GROUP_NAMES = NO +SORT_BY_SCOPE_NAME = NO +STRICT_PROTO_MATCHING = NO +GENERATE_TODOLIST = YES +GENERATE_TESTLIST = YES +GENERATE_BUGLIST = YES +GENERATE_DEPRECATEDLIST= YES +ENABLED_SECTIONS = +MAX_INITIALIZER_LINES = 30 +SHOW_USED_FILES = YES +SHOW_FILES = YES +SHOW_NAMESPACES = YES +FILE_VERSION_FILTER = +LAYOUT_FILE = +CITE_BIB_FILES = +EXTERNAL_TOOL_PATH = +#--------------------------------------------------------------------------- +# Configuration options related to warning and progress messages +#--------------------------------------------------------------------------- +QUIET = NO +WARNINGS = YES +WARN_IF_UNDOCUMENTED = YES +WARN_IF_DOC_ERROR = YES +WARN_IF_INCOMPLETE_DOC = YES +WARN_NO_PARAMDOC = NO +WARN_IF_UNDOC_ENUM_VAL = NO +WARN_LAYOUT_FILE = YES +WARN_AS_ERROR = NO +WARN_FORMAT = "$file:$line: $text" +WARN_LINE_FORMAT = "at line $line of file $file" +WARN_LOGFILE = +#--------------------------------------------------------------------------- +# Configuration options related to the input files +#--------------------------------------------------------------------------- +INPUT = src server.py README.md +INPUT_ENCODING = UTF-8 +INPUT_FILE_ENCODING = +FILE_PATTERNS = *.py *.md + *.cc \ + *.cxx \ + *.cxxm \ + *.cpp \ + *.cppm \ + *.ccm \ + *.c++ \ + *.c++m \ + *.java \ + *.ii \ + *.ixx \ + *.ipp \ + *.i++ \ + *.inl \ + *.idl \ + *.ddl \ + *.odl \ + *.h \ + *.hh \ + *.hxx \ + *.hpp \ + *.h++ \ + *.l \ + *.cs \ + *.d \ + *.php \ + *.php4 \ + *.php5 \ + *.phtml \ + *.inc \ + *.m \ + *.markdown \ + *.md \ + *.mm \ + *.dox \ + *.py \ + *.pyw \ + *.f90 \ + *.f95 \ + *.f03 \ + *.f08 \ + *.f18 \ + *.f \ + *.for \ + *.vhd \ + *.vhdl \ + *.ucf \ + *.qsf \ + *.ice +RECURSIVE = YES +EXCLUDE = +EXCLUDE_SYMLINKS = NO +EXCLUDE_PATTERNS = +EXCLUDE_SYMBOLS = +EXAMPLE_PATH = +EXAMPLE_PATTERNS = * +EXAMPLE_RECURSIVE = NO +IMAGE_PATH = +INPUT_FILTER = +FILTER_PATTERNS = +FILTER_SOURCE_FILES = NO +FILTER_SOURCE_PATTERNS = +USE_MDFILE_AS_MAINPAGE = README.md +IMPLICIT_DIR_DOCS = YES +FORTRAN_COMMENT_AFTER = 72 +#--------------------------------------------------------------------------- +# Configuration options related to source browsing +#--------------------------------------------------------------------------- +SOURCE_BROWSER = NO +INLINE_SOURCES = NO +STRIP_CODE_COMMENTS = YES +REFERENCED_BY_RELATION = NO +REFERENCES_RELATION = NO +REFERENCES_LINK_SOURCE = YES +SOURCE_TOOLTIPS = YES +USE_HTAGS = NO +VERBATIM_HEADERS = YES +CLANG_ASSISTED_PARSING = NO +CLANG_ADD_INC_PATHS = YES +CLANG_OPTIONS = +CLANG_DATABASE_PATH = +#--------------------------------------------------------------------------- +# Configuration options related to the alphabetical class index +#--------------------------------------------------------------------------- +ALPHABETICAL_INDEX = YES +IGNORE_PREFIX = +#--------------------------------------------------------------------------- +# Configuration options related to the HTML output +#--------------------------------------------------------------------------- +GENERATE_HTML = YES +HTML_OUTPUT = html +HTML_FILE_EXTENSION = .html +HTML_HEADER = +HTML_FOOTER = +HTML_STYLESHEET = +HTML_EXTRA_STYLESHEET = +HTML_EXTRA_FILES = +HTML_COLORSTYLE = AUTO_LIGHT +HTML_COLORSTYLE_HUE = 220 +HTML_COLORSTYLE_SAT = 100 +HTML_COLORSTYLE_GAMMA = 80 +HTML_DYNAMIC_MENUS = YES +HTML_DYNAMIC_SECTIONS = NO +HTML_CODE_FOLDING = YES +HTML_COPY_CLIPBOARD = YES +HTML_PROJECT_COOKIE = +HTML_INDEX_NUM_ENTRIES = 100 +GENERATE_DOCSET = NO +DOCSET_FEEDNAME = "Doxygen generated docs" +DOCSET_FEEDURL = +DOCSET_BUNDLE_ID = org.doxygen.Project +DOCSET_PUBLISHER_ID = org.doxygen.Publisher +DOCSET_PUBLISHER_NAME = Publisher +GENERATE_HTMLHELP = NO +CHM_FILE = +HHC_LOCATION = +GENERATE_CHI = NO +CHM_INDEX_ENCODING = +BINARY_TOC = NO +TOC_EXPAND = NO +SITEMAP_URL = +GENERATE_QHP = NO +QCH_FILE = +QHP_NAMESPACE = org.doxygen.Project +QHP_VIRTUAL_FOLDER = doc +QHP_CUST_FILTER_NAME = +QHP_CUST_FILTER_ATTRS = +QHP_SECT_FILTER_ATTRS = +QHG_LOCATION = +GENERATE_ECLIPSEHELP = NO +ECLIPSE_DOC_ID = org.doxygen.Project +DISABLE_INDEX = NO +GENERATE_TREEVIEW = YES +PAGE_OUTLINE_PANEL = YES +FULL_SIDEBAR = NO +ENUM_VALUES_PER_LINE = 4 +SHOW_ENUM_VALUES = NO +TREEVIEW_WIDTH = 250 +EXT_LINKS_IN_WINDOW = NO +OBFUSCATE_EMAILS = YES +HTML_FORMULA_FORMAT = png +FORMULA_FONTSIZE = 10 +FORMULA_MACROFILE = +USE_MATHJAX = NO +MATHJAX_VERSION = MathJax_2 +MATHJAX_FORMAT = HTML-CSS +MATHJAX_RELPATH = +MATHJAX_EXTENSIONS = +MATHJAX_CODEFILE = +SEARCHENGINE = YES +SERVER_BASED_SEARCH = NO +EXTERNAL_SEARCH = NO +SEARCHENGINE_URL = +SEARCHDATA_FILE = searchdata.xml +EXTERNAL_SEARCH_ID = +EXTRA_SEARCH_MAPPINGS = +#--------------------------------------------------------------------------- +# Configuration options related to the LaTeX output +#--------------------------------------------------------------------------- +GENERATE_LATEX = NO +LATEX_OUTPUT = latex +LATEX_CMD_NAME = +MAKEINDEX_CMD_NAME = makeindex +LATEX_MAKEINDEX_CMD = makeindex +COMPACT_LATEX = NO +PAPER_TYPE = a4 +EXTRA_PACKAGES = +LATEX_HEADER = +LATEX_FOOTER = +LATEX_EXTRA_STYLESHEET = +LATEX_EXTRA_FILES = +PDF_HYPERLINKS = YES +USE_PDFLATEX = YES +LATEX_BATCHMODE = NO +LATEX_HIDE_INDICES = NO +LATEX_BIB_STYLE = plainnat +LATEX_EMOJI_DIRECTORY = +#--------------------------------------------------------------------------- +# Configuration options related to the RTF output +#--------------------------------------------------------------------------- +GENERATE_RTF = NO +RTF_OUTPUT = rtf +COMPACT_RTF = NO +RTF_HYPERLINKS = NO +RTF_STYLESHEET_FILE = +RTF_EXTENSIONS_FILE = +RTF_EXTRA_FILES = +#--------------------------------------------------------------------------- +# Configuration options related to the man page output +#--------------------------------------------------------------------------- +GENERATE_MAN = NO +MAN_OUTPUT = man +MAN_EXTENSION = .3 +MAN_SUBDIR = +MAN_LINKS = NO +#--------------------------------------------------------------------------- +# Configuration options related to the XML output +#--------------------------------------------------------------------------- +GENERATE_XML = NO +XML_OUTPUT = xml +XML_PROGRAMLISTING = YES +XML_NS_MEMB_FILE_SCOPE = NO +#--------------------------------------------------------------------------- +# Configuration options related to the DOCBOOK output +#--------------------------------------------------------------------------- +GENERATE_DOCBOOK = NO +DOCBOOK_OUTPUT = docbook +#--------------------------------------------------------------------------- +# Configuration options for the AutoGen Definitions output +#--------------------------------------------------------------------------- +GENERATE_AUTOGEN_DEF = NO +#--------------------------------------------------------------------------- +# Configuration options related to Sqlite3 output +#--------------------------------------------------------------------------- +GENERATE_SQLITE3 = NO +SQLITE3_OUTPUT = sqlite3 +SQLITE3_RECREATE_DB = YES +#--------------------------------------------------------------------------- +# Configuration options related to the Perl module output +#--------------------------------------------------------------------------- +GENERATE_PERLMOD = NO +PERLMOD_LATEX = NO +PERLMOD_PRETTY = YES +PERLMOD_MAKEVAR_PREFIX = +#--------------------------------------------------------------------------- +# Configuration options related to the preprocessor +#--------------------------------------------------------------------------- +ENABLE_PREPROCESSING = YES +MACRO_EXPANSION = NO +EXPAND_ONLY_PREDEF = NO +SEARCH_INCLUDES = YES +INCLUDE_PATH = +INCLUDE_FILE_PATTERNS = +PREDEFINED = +EXPAND_AS_DEFINED = +SKIP_FUNCTION_MACROS = YES +#--------------------------------------------------------------------------- +# Configuration options related to external references +#--------------------------------------------------------------------------- +TAGFILES = +GENERATE_TAGFILE = +ALLEXTERNALS = NO +EXTERNAL_GROUPS = YES +EXTERNAL_PAGES = YES +#--------------------------------------------------------------------------- +# Configuration options related to diagram generator tools +#--------------------------------------------------------------------------- +HIDE_UNDOC_RELATIONS = YES +HAVE_DOT = NO +DOT_NUM_THREADS = 0 +DOT_COMMON_ATTR = "fontname=Helvetica,fontsize=10" +DOT_EDGE_ATTR = "labelfontname=Helvetica,labelfontsize=10" +DOT_NODE_ATTR = "shape=box,height=0.2,width=0.4" +DOT_FONTPATH = +CLASS_GRAPH = YES +COLLABORATION_GRAPH = YES +GROUP_GRAPHS = YES +UML_LOOK = NO +UML_LIMIT_NUM_FIELDS = 10 +UML_MAX_EDGE_LABELS = 10 +DOT_UML_DETAILS = NO +DOT_WRAP_THRESHOLD = 17 +TEMPLATE_RELATIONS = NO +INCLUDE_GRAPH = YES +INCLUDED_BY_GRAPH = YES +CALL_GRAPH = NO +CALLER_GRAPH = NO +GRAPHICAL_HIERARCHY = YES +DIRECTORY_GRAPH = YES +DIR_GRAPH_MAX_DEPTH = 1 +DOT_IMAGE_FORMAT = png +INTERACTIVE_SVG = NO +DOT_PATH = +DOTFILE_DIRS = +DIA_PATH = +DIAFILE_DIRS = +PLANTUML_JAR_PATH = +PLANTUML_CFG_FILE = +PLANTUML_INCLUDE_PATH = +PLANTUMLFILE_DIRS = +DOT_GRAPH_MAX_NODES = 50 +MAX_DOT_GRAPH_DEPTH = 0 +DOT_MULTI_TARGETS = NO +GENERATE_LEGEND = YES +DOT_CLEANUP = YES +MSCGEN_TOOL = +MSCFILE_DIRS = diff --git a/README.md b/README.md index e03ba85..2753b2d 100644 --- a/README.md +++ b/README.md @@ -1,2 +1,120 @@ -# 055-higher-lower +# ๐Ÿš€ Higher or Lower +Day 55 of Udemy's *100 Days of Code: The Complete Python Pro Bootcamp*: a Higher or Lower guessing game as a Flask website, written for fellow course participants and for anyone who browses the repository for ideas. + +## ๐Ÿ“š Table of Contents + +- [Overview](#-overview) +- [Requirements](#-requirements) +- [Setup](#-setup) +- [Run](#-run) +- [Tests](#-tests) +- [License](#-license) +- [Links](#-links) +- [Appendix: Project documents](#-appendix-project-documents) + +## ๐Ÿงญ Overview + +The site picks a secret number between 0 and 9. Open `/` for the start page, then guess by putting a number in the URL, for example `/3`. The page tells you whether the guess is too low, too high or correct, with a different heading colour and GIF for each answer. + +The repository also holds the small Flask programs of the day's lectures: URL paths, rendering HTML and decorators. + +| Part | What it is for | +| --- | --- | +| `server.py` | Starts the game, as the assignment asks | +| `src/higher_lower/` | The game, split in layers: `domain`, `application`, `infrastructure`, `presentation` | +| `src/higher_lower/constants.py` | Every heading, colour, GIF and number range in one place | +| `tests/` | pytest tests | +| `docs/` | Project documents (business case, plan, milestones, reviews) | +| `Doxyfile` | Settings to generate API documentation with Doxygen | + +## ๐Ÿ“‹ Requirements + +- Python 3.13 or later, to run the code. +- Flask, the only runtime dependency, installed by the setup below. +- pytest, to run the tests (installed with the `test` extra). +- Doxygen, only if you want to generate the API documentation. + +## ๐Ÿ› ๏ธ Setup + +Create a local virtual environment named `.venv` in the project folder, activate it, upgrade pip and install the project. + +Windows (PowerShell): + +```powershell +python -m venv .venv +.\.venv\Scripts\Activate.ps1 +python -m pip install --upgrade pip +python -m pip install -e ".[test]" +``` + +Linux and macOS: + +```bash +python3 -m venv .venv +source .venv/bin/activate +python -m pip install --upgrade pip +python -m pip install -e ".[test]" +``` + +While the environment is active, the prompt starts with `(.venv)`. Leave it with `deactivate`. Delete the `.venv` folder to start over. + +## โ–ถ๏ธ Run + +```bash +python server.py +``` + +Open `http://127.0.0.1:5000/` in a browser, then try `http://127.0.0.1:5000/3`. + +## ๐Ÿงช Tests + +```bash +python -m pytest +``` + +Generate the API documentation with Doxygen into `build/html`: + +```bash +doxygen Doxyfile +``` + +## ๐Ÿ“„ License + +GNU Affero General Public License v3.0, see [LICENSE][license]. + +## ๐Ÿ”— Links + +- [Repository][repository] +- [Documentation][documentation] +- [Issue tracker][issues] + +## ๐Ÿ“Ž Appendix: Project documents + +The documents a newcomer needs, in reading order. + +| Document | What it tells you | +| --- | --- | +| [AGENTS.md][agents] | The rules AI agents follow in this repository | +| [Business Case][BC-001] | Why the project exists, its scope and success criteria | +| [Stakeholder Analysis][SA-001] | Who is involved; the stakeholder IDs used for owners and reviewers | +| [Project Plan][PP-001] | The gateways and their schedule | +| [Milestones][milestones] | One document per gateway: Go/No-Go criteria and tasks | +| [Artifact registry][registry] | Where each artifact type lives, the next version, the PO language and domain | +| [Framework README][framework-readme] | The framework this project uses | +| [Framework changelog][framework-changelog] | What changed in each framework release | + +--- + +[license]: ./LICENSE +[repository]: https://git.tirsystem.com/Tirsvad-Udemy-100-days-of-code/055-higher-lower +[documentation]: ./docs/ +[issues]: https://git.tirsystem.com/Tirsvad-Udemy-100-days-of-code/055-higher-lower/issues +[agents]: ./AGENTS.md +[BC-001]: ./docs/business-case.md +[SA-001]: ./docs/stakeholder-analysis.md +[PP-001]: ./docs/project-plan.md +[milestones]: ./docs/milestones/ +[registry]: ./docs/artifact-registry.md +[framework-readme]: ./framework/README.md +[framework-changelog]: ./framework/CHANGELOG.md diff --git a/docs/artifact-registry.md b/docs/artifact-registry.md index 862d9d6..9f633ef 100644 --- a/docs/artifact-registry.md +++ b/docs/artifact-registry.md @@ -15,7 +15,7 @@ document of a type. `Primary File` may contain a glob (e.g. | SA | Stakeholder Analysis | docs/stakeholder-analysis.md | 002 | | PP | Project Plan | docs/project-plan.md | 002 | | MIL | Milestone / Gateway | docs/milestones/*.md | 005 | -| RC | SQA Review Record | docs/sqa/reviews/rc-*.md | 008 | +| RC | SQA Review Record | docs/sqa/reviews/rc-*.md | 009 | ## Languages diff --git a/docs/sqa/reviews/rc-008-code-mil-001.md b/docs/sqa/reviews/rc-008-code-mil-001.md new file mode 100644 index 0000000..c679fb4 --- /dev/null +++ b/docs/sqa/reviews/rc-008-code-mil-001.md @@ -0,0 +1,61 @@ +# RC-008 Code review of MIL-001 + +## Metadata +| Key | Value | +| --- | --- | +| ID | RC-008 | +| CrossReference | [MIL-001], [QC-PY-001] | + +## Version History +| Date | Status | Author | Reviewer | Change | Commit | +| --- | --- | --- | --- | --- | --- | +| 2026-11-06 | Accepted | Jens Tirsvad Nielsen | AI as stand-in for S01 | Initial version | pending | + +--- + +## Artifact Under Review + +- Instance reviewed: [MIL-001] +- Checklist used: [QC-PY-001] +- Scope: Code of MIL-001: `src/higher_lower/constants.py`, layer packages, `tests/unit/test_constants.py`, and the project configuration +- Language and domain: n/a (technical type) +- Language reviewer: none +- Mode: autonomous, not independent (the reviewer is `AI as stand-in for S01`) + +## Checklist Results + +| # | Criterion | Status | Evidence/Notes | +| --- | --- | --- | --- | +| 1 | Packages, modules, functions, variables, classes and constants follow PEP 8 casing (`snake_case`, `PascalCase`, `UPPER_SNAKE`) | Pass | Modules and functions use snake_case, classes PascalCase, constants UPPER_SNAKE | +| 2 | Names state purpose in the domain's language; no unexplained abbreviations, no single-letter names outside tiny scopes | Pass | Names state purpose (`compare_guess`, `GuessResult`, `HOME_HEADING`); no unexplained abbreviations | +| 3 | Code is produced by the project's formatter and passes its linter with no unexplained suppressions | Pass | `ruff check` and `ruff format --check` report no finding; no suppressions | +| 4 | Every function and method signature is type-annotated, including `-> None` | Pass | Every signature is annotated; `mypy --strict` reports no issue | +| 5 | No bare `except:`, no swallowed exceptions; specific exceptions are raised and the cause is kept (`raise ... from`) | Pass | No bare `except`; no exception is swallowed | +| 6 | No mutable default arguments and no shadowed builtins | Pass | No mutable default arguments; no builtin is shadowed | +| 7 | Files, locks and connections are managed with context managers | N-A | The code opens no file, lock or connection | +| 8 | Public modules, classes and functions have docstrings that say what, not how | Pass | Public modules, classes and functions have Doxygen-style docstrings | +| 9 | Logging uses `logging`, not `print`; no secrets or personal data in log output | Pass | No `print`; no secret in the code; `.env` is neither read nor imported | +| 10 | Classes and operations trace to the Design Class Diagram they implement; deviations are recorded | N-A | No DCD exists: the milestone tasks are plain technical tasks (see PP-001 Open Issues) | +| 11 | Tests exist for new behaviour, are named for the behaviour, and do not depend on order or the network | Pass | pytest tests are named for behaviour, run in any order and use no network | +| 12 | Type checker runs in strict mode without errors; `Any` is justified in a comment | Pass | `mypy --strict` passes; no `Any` | +| 13 | Dependencies are declared and pinned in the project's dependency file, none unused | Pass | `pyproject.toml` declares Flask (runtime) and pytest, ruff, mypy (extras); none unused | +| 14 | Each piece of knowledge (a business rule, constant, format, validation or query) is defined in one place; code is merged only where it expresses the same knowledge, not where it merely looks alike | Pass | Headings, colours, GIFs and range are defined once in `constants.py` | +| 15 | Imports point inward: business-rule modules import no framework, database, UI or delivery-mechanism code, and there are no import cycles | Pass | Only `constants.py` exists; it imports nothing | +| 16 | SOLID holds: a class or module has one reason to change; new behaviour is added by extension, not by editing a type test in several places; subclasses honour the contract of their base; protocols are narrow; high-level code depends on protocols or abstract types and receives its implementations | Pass | Each module has one reason to change; behaviour is added by extension | +| 17 | Source is laid out in the layers and folders of the clean architecture folder structure (`domain`, `application`, `infrastructure`, `presentation` packages under `src/`, and `unit`, `integration` and `e2e` under `tests/`), in `snake_case`, and imports between the layers point inward | Pass | The four layer packages exist under `src/higher_lower/`; tests are under `tests/unit`; the layers are filled by MIL-003 | +| 18 | File and folder names are English, contain no space and no character outside letters, digits, `-`, `_` and `.`, and follow the casing of the language for files | Pass | File and folder names are English with letters, digits and `_` only | + +## Overall Verdict + +Go โ€” All criteria pass or are not applicable; no blocking finding. + +## Action Items + +| Action | Owner | Due | +| --- | --- | --- | +| None | S01 | 2026-11-06 | + +--- + +[MIL-001]: ../../docs/milestones/mil-001-project-setup.md +[QC-PY-001]: ../../framework/qc/code/qc-programming-python.md diff --git a/pyproject.toml b/pyproject.toml new file mode 100644 index 0000000..de51cc2 --- /dev/null +++ b/pyproject.toml @@ -0,0 +1,42 @@ +[build-system] +requires = ["setuptools>=68"] +build-backend = "setuptools.build_meta" + +[project] +name = "higher-lower" +version = "0.1.0" +description = "Day 55 of Udemy's 100 Days of Code: a Higher or Lower guessing game as a Flask website." +readme = "README.md" +requires-python = ">=3.13" +license = { file = "LICENSE" } +dependencies = [ + "flask>=3.0", +] + +[project.optional-dependencies] +test = [ + "pytest>=8.0", +] +dev = [ + "pytest>=8.0", + "ruff>=0.6", + "mypy>=1.10", +] + +[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", "B", "UP", "N"] + +[tool.mypy] +strict = true +files = ["src", "tests"] diff --git a/src/higher_lower/__init__.py b/src/higher_lower/__init__.py new file mode 100644 index 0000000..0694cc8 --- /dev/null +++ b/src/higher_lower/__init__.py @@ -0,0 +1,4 @@ +"""Higher or Lower: Day 55 of Udemy's 100 Days of Code as a Flask website. + +@brief Package root of the Higher or Lower project. +""" diff --git a/src/higher_lower/application/__init__.py b/src/higher_lower/application/__init__.py new file mode 100644 index 0000000..96b5122 --- /dev/null +++ b/src/higher_lower/application/__init__.py @@ -0,0 +1,4 @@ +"""Application layer of the Higher or Lower project. + +@brief Application layer. +""" diff --git a/src/higher_lower/constants.py b/src/higher_lower/constants.py new file mode 100644 index 0000000..2dead5b --- /dev/null +++ b/src/higher_lower/constants.py @@ -0,0 +1,45 @@ +"""Constants of the Higher or Lower project. + +@brief Every literal the game shows or compares lives here, in one place. +""" + +## Lowest number the secret number can be. +MIN_NUMBER: int = 0 +## Highest number the secret number can be. +MAX_NUMBER: int = 9 + +## Heading of the home page. +HOME_HEADING: str = f"Guess a number between {MIN_NUMBER} and {MAX_NUMBER}" +## Heading when the guess is lower than the secret number. +LOW_HEADING: str = "Too low, try again!" +## Heading when the guess is higher than the secret number. +HIGH_HEADING: str = "Too high, try again!" +## Heading when the guess equals the secret number. +CORRECT_HEADING: str = "You found me!" +## Heading when the guess is outside the allowed range. +OUT_OF_RANGE_HEADING: str = f"Please guess between {MIN_NUMBER} and {MAX_NUMBER}" + +## Heading colour of the home page. +HOME_COLOUR: str = "magenta" +## Heading colour for a guess that is too low. +LOW_COLOUR: str = "red" +## Heading colour for a guess that is too high. +HIGH_COLOUR: str = "purple" +## Heading colour for a correct guess. +CORRECT_COLOUR: str = "green" +## Heading colour for a guess outside the range. +OUT_OF_RANGE_COLOUR: str = "orange" + +## GIF of the home page. +HOME_GIF: str = "https://media.giphy.com/media/3o7aCSPqXE5C6T8tBC/giphy.gif" +## GIF for a guess that is too low. +LOW_GIF: str = "https://media.giphy.com/media/jD4DwBtqPXRXa/giphy.gif" +## GIF for a guess that is too high. +HIGH_GIF: str = "https://media.giphy.com/media/3o6ZtaO9BZHcOjmErm/giphy.gif" +## GIF for a correct guess. +CORRECT_GIF: str = "https://media.giphy.com/media/4T7e4DmcrP9du/giphy.gif" + +## Host the development server listens on. +HOST: str = "127.0.0.1" +## Port the development server listens on. +PORT: int = 5000 diff --git a/src/higher_lower/domain/__init__.py b/src/higher_lower/domain/__init__.py new file mode 100644 index 0000000..68a896d --- /dev/null +++ b/src/higher_lower/domain/__init__.py @@ -0,0 +1,4 @@ +"""Domain layer of the Higher or Lower project. + +@brief Domain layer. +""" diff --git a/src/higher_lower/infrastructure/__init__.py b/src/higher_lower/infrastructure/__init__.py new file mode 100644 index 0000000..7cf0119 --- /dev/null +++ b/src/higher_lower/infrastructure/__init__.py @@ -0,0 +1,4 @@ +"""Infrastructure layer of the Higher or Lower project. + +@brief Infrastructure layer. +""" diff --git a/src/higher_lower/presentation/__init__.py b/src/higher_lower/presentation/__init__.py new file mode 100644 index 0000000..e663d59 --- /dev/null +++ b/src/higher_lower/presentation/__init__.py @@ -0,0 +1,4 @@ +"""Presentation layer of the Higher or Lower project. + +@brief Presentation layer. +""" diff --git a/tests/unit/test_constants.py b/tests/unit/test_constants.py new file mode 100644 index 0000000..68807d0 --- /dev/null +++ b/tests/unit/test_constants.py @@ -0,0 +1,21 @@ +"""Tests of the project constants.""" + +from higher_lower import constants + + +def test_range_is_ordered() -> None: + assert constants.MIN_NUMBER < constants.MAX_NUMBER + + +def test_home_heading_names_the_range() -> None: + assert str(constants.MIN_NUMBER) in constants.HOME_HEADING + assert str(constants.MAX_NUMBER) in constants.HOME_HEADING + + +def test_answer_colours_are_different() -> None: + colours = { + constants.LOW_COLOUR, + constants.HIGH_COLOUR, + constants.CORRECT_COLOUR, + } + assert len(colours) == 3 -- 2.54.0 From ade7da5d2b5f0103c4d39c241726390d972ddbd3 Mon Sep 17 00:00:00 2001 From: Jens Tirsvad Nielsen Date: Fri, 6 Nov 2026 12:28:22 +0800 Subject: [PATCH 2/2] Link the synced milestones in the plan and resolve the RC-008 commit link --- docs/project-plan.md | 185 ++++++++++++------------ docs/sqa/reviews/rc-008-code-mil-001.md | 3 +- 2 files changed, 96 insertions(+), 92 deletions(-) diff --git a/docs/project-plan.md b/docs/project-plan.md index b216f11..166727e 100644 --- a/docs/project-plan.md +++ b/docs/project-plan.md @@ -1,91 +1,94 @@ -# Project Plan - -## Metadata -| Key | Value | -| --- | --- | -| ID | PP-001 | -| CrossReference | [BC-001], [SA-001] | -| Language | en | -| Domain | it | - -## Version History -| Date | Status | Author | Reviewer | Change | Commit | -| --- | --- | --- | --- | --- | --- | -| 2026-11-06 | Accepted | Jens Tirsvad Nielsen | AI as stand-in for S01 | Initial version | [42b3a09] | - ---- -## Purpose - -This plan schedules the four phases that deliver the Higher or Lower Flask project within the few-day effort stated in [BC-001]. S01 is the Product Owner and owns every phase; [SA-001] sets the cadence: one reviewed pull request per phase. - -## Planning Assumptions - -- Week 1 starts 2026-11-06; the plan ends by 2026-11-16, the few-day effort of [BC-001] Constraints; the dates are the planner's estimate, accepted by S01 in chat on 2026-11-06. -- Phase length: two to three days each; one branch and one pull request per phase. -- Autonomous mode: the AI acts as stand-in reviewer for S01 and every review record says so. -- The Milestone column stays blank (not yet synced) until the host sync runs. -- Tokens come from `.env`, which is ignored by git and never imported by the project. - -## Gateway Schedule - -| Gateway | Document | Window | Decision date | Owner | Stories | Main deliverable | Milestone | -| --- | --- | --- | --- | --- | --- | --- | --- | -| Project setup | [MIL-001] | 2026-11-06 to 2026-11-08 | 2026-11-08 | S01 | none (technical tasks) | Skeleton, tooling, README, repository metadata | | -| Lecture steps | [MIL-002] | 2026-11-08 to 2026-11-10 | 2026-11-10 | S01 | none (technical tasks) | Routes, HTML and decorator modules with tests | | -| Higher or Lower game | [MIL-003] | 2026-11-10 to 2026-11-12 | 2026-11-12 | S01 | none (technical tasks) | The final project with tests | | -| Docs, screenshots and wiki | [MIL-004] | 2026-11-12 to 2026-11-16 | 2026-11-16 | S01 | none (technical tasks) | Screenshots, README, wiki in en, da, ms | | - -```plantuml -@startgantt -Project starts 2026-11-06 -[Project setup] starts 2026-11-06 and ends 2026-11-08 -[Project setup Go/No-Go] happens 2026-11-08 -[Lecture steps] starts 2026-11-08 and ends 2026-11-10 -[Lecture steps Go/No-Go] happens 2026-11-10 -[Higher or Lower game] starts 2026-11-10 and ends 2026-11-12 -[Higher or Lower game Go/No-Go] happens 2026-11-12 -[Docs, screenshots and wiki] starts 2026-11-12 and ends 2026-11-16 -[Docs Go/No-Go] happens 2026-11-16 -@endgantt -``` - -## Scope Coverage - -| Business Case scope item | Gateway | -| --- | --- | -| Flask application in `src/`, tests in `tests/` | MIL-002, MIL-003 | -| `constants.py`, `pyproject.toml`, `.gitignore`, Doxygen comments, `Doxyfile` | MIL-001 | -| README from the framework template | MIL-001, MIL-004 | -| Screenshots and wiki in en, da, ms | MIL-004 | -| Repository description and topics | MIL-001 | - -## Dependencies - -``` -MIL-001 โ†’ MIL-002 โ†’ MIL-003 โ†’ MIL-004 -``` - -A No-Go on a phase stops the later phases; their dates and the end date move by the length of the rework, and S01 decides the move. - -## Plan Risks - -| Risk | Impact | Mitigation | -| --- | --- | --- | -| Docker Desktop is not running on the host, so screenshots cannot be taken in a container (BC-001 risk: screenshots need a browser) | MIL-004 blocked | Start Docker Desktop, or use Windows Sandbox; stop and report if neither is available | -| The three-language wiki takes longer than planned (BC-001 risk: translation errors in da or ms) | MIL-004 slips | Keep pages short and structurally identical | - -## Open Issues - -- The user named `https://git.tirsystem.com/Tirsvad-Udemy-100_days_of_code`; `origin` points at `Tirsvad-Udemy-100-days-of-code/055-higher-lower`. The plan uses `origin`; S01 can correct this at plan acceptance. -- The tasks are plain technical tasks with no use case, because the assignment text is the specification; a use case is added if the reviewer asks for one. -- The wiki is written as files in the repository (`docs/wiki/en`, `da`, `ms`) and published to the host wiki only if the host exposes it. - ---- - -[BC-001]: ./business-case.md -[SA-001]: ./stakeholder-analysis.md -[MIL-001]: ./milestones/mil-001-project-setup.md -[MIL-002]: ./milestones/mil-002-lecture-steps.md -[MIL-003]: ./milestones/mil-003-higher-lower-game.md -[MIL-004]: ./milestones/mil-004-docs-screenshots-wiki.md -[42b3a09]: https://git.tirsystem.com/Tirsvad-Udemy-100-days-of-code/055-higher-lower/commit/42b3a093b773c9743ae3c104e1c30bf3dc480d7c +# Project Plan + +## Metadata +| Key | Value | +| --- | --- | +| ID | PP-001 | +| CrossReference | [BC-001], [SA-001] | +| Language | en | +| Domain | it | + +## Version History +| Date | Status | Author | Reviewer | Change | Commit | +| --- | --- | --- | --- | --- | --- | +| 2026-11-06 | Accepted | Jens Tirsvad Nielsen | AI as stand-in for S01 | Initial version | [42b3a09] | + +--- +## Purpose + +This plan schedules the four phases that deliver the Higher or Lower Flask project within the few-day effort stated in [BC-001]. S01 is the Product Owner and owns every phase; [SA-001] sets the cadence: one reviewed pull request per phase. + +## Planning Assumptions + +- Week 1 starts 2026-11-06; the plan ends by 2026-11-16, the few-day effort of [BC-001] Constraints; the dates are the planner's estimate, accepted by S01 in chat on 2026-11-06. +- Phase length: two to three days each; one branch and one pull request per phase. +- Autonomous mode: the AI acts as stand-in reviewer for S01 and every review record says so. +- Tokens come from `.env`, which is ignored by git and never imported by the project. + +## Gateway Schedule + +| Gateway | Document | Window | Decision date | Owner | Stories | Main deliverable | Milestone | +| --- | --- | --- | --- | --- | --- | --- | --- | +| Project setup | [MIL-001] | 2026-11-06 to 2026-11-08 | 2026-11-08 | S01 | none (technical tasks) | Skeleton, tooling, README, repository metadata | [MS-001] | +| Lecture steps | [MIL-002] | 2026-11-08 to 2026-11-10 | 2026-11-10 | S01 | none (technical tasks) | Routes, HTML and decorator modules with tests | [MS-002] | +| Higher or Lower game | [MIL-003] | 2026-11-10 to 2026-11-12 | 2026-11-12 | S01 | none (technical tasks) | The final project with tests | [MS-003] | +| Docs, screenshots and wiki | [MIL-004] | 2026-11-12 to 2026-11-16 | 2026-11-16 | S01 | none (technical tasks) | Screenshots, README, wiki in en, da, ms | [MS-004] | + +```plantuml +@startgantt +Project starts 2026-11-06 +[Project setup] starts 2026-11-06 and ends 2026-11-08 +[Project setup Go/No-Go] happens 2026-11-08 +[Lecture steps] starts 2026-11-08 and ends 2026-11-10 +[Lecture steps Go/No-Go] happens 2026-11-10 +[Higher or Lower game] starts 2026-11-10 and ends 2026-11-12 +[Higher or Lower game Go/No-Go] happens 2026-11-12 +[Docs, screenshots and wiki] starts 2026-11-12 and ends 2026-11-16 +[Docs Go/No-Go] happens 2026-11-16 +@endgantt +``` + +## Scope Coverage + +| Business Case scope item | Gateway | +| --- | --- | +| Flask application in `src/`, tests in `tests/` | MIL-002, MIL-003 | +| `constants.py`, `pyproject.toml`, `.gitignore`, Doxygen comments, `Doxyfile` | MIL-001 | +| README from the framework template | MIL-001, MIL-004 | +| Screenshots and wiki in en, da, ms | MIL-004 | +| Repository description and topics | MIL-001 | + +## Dependencies + +``` +MIL-001 โ†’ MIL-002 โ†’ MIL-003 โ†’ MIL-004 +``` + +A No-Go on a phase stops the later phases; their dates and the end date move by the length of the rework, and S01 decides the move. + +## Plan Risks + +| Risk | Impact | Mitigation | +| --- | --- | --- | +| Docker Desktop is not running on the host, so screenshots cannot be taken in a container (BC-001 risk: screenshots need a browser) | MIL-004 blocked | Start Docker Desktop, or use Windows Sandbox; stop and report if neither is available | +| The three-language wiki takes longer than planned (BC-001 risk: translation errors in da or ms) | MIL-004 slips | Keep pages short and structurally identical | + +## Open Issues + +- The user named `https://git.tirsystem.com/Tirsvad-Udemy-100_days_of_code`; `origin` points at `Tirsvad-Udemy-100-days-of-code/055-higher-lower`. The plan uses `origin`; S01 can correct this at plan acceptance. +- The tasks are plain technical tasks with no use case, because the assignment text is the specification; a use case is added if the reviewer asks for one. +- The wiki is written as flat files in `docs/wiki/` (English `Page.md`, Danish `Page-da.md`, Bahasa Malaysia `Page-ms.md`), as `framework/process/wiki.md` requires; the framework workflow publishes it to the host wiki after merge. + +--- + +[BC-001]: ./business-case.md +[SA-001]: ./stakeholder-analysis.md +[MIL-001]: ./milestones/mil-001-project-setup.md +[MIL-002]: ./milestones/mil-002-lecture-steps.md +[MIL-003]: ./milestones/mil-003-higher-lower-game.md +[MIL-004]: ./milestones/mil-004-docs-screenshots-wiki.md +[42b3a09]: https://git.tirsystem.com/Tirsvad-Udemy-100-days-of-code/055-higher-lower/commit/42b3a093b773c9743ae3c104e1c30bf3dc480d7c +[MS-001]: https://git.tirsystem.com/Tirsvad-Udemy-100-days-of-code/055-higher-lower/milestone/347 +[MS-002]: https://git.tirsystem.com/Tirsvad-Udemy-100-days-of-code/055-higher-lower/milestone/348 +[MS-003]: https://git.tirsystem.com/Tirsvad-Udemy-100-days-of-code/055-higher-lower/milestone/349 +[MS-004]: https://git.tirsystem.com/Tirsvad-Udemy-100-days-of-code/055-higher-lower/milestone/350 diff --git a/docs/sqa/reviews/rc-008-code-mil-001.md b/docs/sqa/reviews/rc-008-code-mil-001.md index c679fb4..cc77262 100644 --- a/docs/sqa/reviews/rc-008-code-mil-001.md +++ b/docs/sqa/reviews/rc-008-code-mil-001.md @@ -9,7 +9,7 @@ ## Version History | Date | Status | Author | Reviewer | Change | Commit | | --- | --- | --- | --- | --- | --- | -| 2026-11-06 | Accepted | Jens Tirsvad Nielsen | AI as stand-in for S01 | Initial version | pending | +| 2026-11-06 | Accepted | Jens Tirsvad Nielsen | AI as stand-in for S01 | Initial version | [5ebc1df] | --- @@ -59,3 +59,4 @@ Go โ€” All criteria pass or are not applicable; no blocking finding. [MIL-001]: ../../docs/milestones/mil-001-project-setup.md [QC-PY-001]: ../../framework/qc/code/qc-programming-python.md +[5ebc1df]: https://git.tirsystem.com/Tirsvad-Udemy-100-days-of-code/055-higher-lower/commit/5ebc1df94a4bf8fefe16db074d71f46bcb13abc4 -- 2.54.0