diff --git a/README.md b/README.md index 8422168..8ea59b7 100644 --- a/README.md +++ b/README.md @@ -56,7 +56,7 @@ Backend (from `server/`): cd server python3 -m venv .venv .venv/bin/pip install -r requirements.txt -.venv/bin/pip install -e ./packages/tavolo-platform -e ./packages/tavolo-scopone -e '.[dev]' +.venv/bin/pip install -e ./packages/tavolo-platform -e ./packages/tavolo-scopone -e './packages/tavolo-app[dev]' .venv/bin/python -m unittest discover -s tests -t . .venv/bin/python -m unittest discover -s packages/tavolo-platform/tests .venv/bin/python -m unittest discover -s packages/tavolo-scopone/tests diff --git a/server/Dockerfile b/server/Dockerfile index d5c61fd..6d7c87e 100644 --- a/server/Dockerfile +++ b/server/Dockerfile @@ -55,14 +55,16 @@ RUN --mount=type=cache,target=/root/.cache/pip \ && /opt/venv/bin/pip install --upgrade pip \ && /opt/venv/bin/pip install -r requirements.txt -COPY server/pyproject.toml server/README.md ./ -COPY server/src/ ./src/ -# Sibling distributions, installed from the local tree (PEP 420 namespace -# packages sharing the `tavolo` namespace with the app above). --no-deps: -# every third-party dependency is already pinned in requirements.txt. +# The three sibling distributions, installed from the local tree (PEP 420 +# namespace packages sharing the `tavolo` namespace). --no-deps: every +# third-party dependency is already pinned in requirements.txt. COPY server/packages/ ./packages/ RUN --mount=type=cache,target=/root/.cache/pip \ - /opt/venv/bin/pip install --no-deps ./packages/tavolo-platform ./packages/tavolo-scopone . + /opt/venv/bin/pip install --no-deps ./packages/tavolo-platform ./packages/tavolo-scopone ./packages/tavolo-app +# server/pyproject.toml only carries the [tool.aerich] section (the +# db-migrate compose service runs `aerich upgrade` with working_dir=/app, +# next to ./migrations). +COPY server/pyproject.toml ./ # aerich migration files are a release artifact: the db-migrate compose # service runs `aerich upgrade` from this image before the app starts. COPY server/migrations/ ./migrations/ diff --git a/server/README.md b/server/README.md index 4a74cf3..9164ffb 100644 --- a/server/README.md +++ b/server/README.md @@ -13,7 +13,7 @@ and [`packages/tavolo-scopone/README.md`](packages/tavolo-scopone/README.md)): - **`tavolo-scopone`** (`packages/tavolo-scopone/`) — scopone scientifico, the four-player, fixed-partnership variant of the classic Italian card game: pure rules plus the platform adapter. -- **`tavolo-app`** (`src/tavolo/`, this `pyproject.toml`) — the +- **`tavolo-app`** (`packages/tavolo-app/`) — the composition root wiring the platform to the scopone game, with the environment-driven settings and the SPA shell. @@ -279,18 +279,15 @@ must dismiss. A play attempted in this phase is rejected with an ```sh python3 -m venv .venv .venv/bin/pip install -r requirements.txt -.venv/bin/pip install -e ./packages/tavolo-platform -e ./packages/tavolo-scopone -e '.[dev]' +.venv/bin/pip install -e ./packages/tavolo-platform -e ./packages/tavolo-scopone -e './packages/tavolo-app[dev]' # app integration suite: .venv/bin/python -m unittest discover -s tests -t . # per-package suites (each package is self-contained): .venv/bin/python -m unittest discover -s packages/tavolo-platform/tests .venv/bin/python -m unittest discover -s packages/tavolo-scopone/tests -# type checks: +# type checks (see packages/tavolo-app/README.md for the app modules): .venv/bin/python -m mypy -p tavolo.platform .venv/bin/python -m mypy -p tavolo.scopone -.venv/bin/python -m mypy --namespace-packages --explicit-package-bases \ - src/tavolo/app.py src/tavolo/config.py src/tavolo/static.py \ - src/tavolo/aerich_config.py src/tavolo/logging_config.py ``` Tests run fully in-process: in-memory sqlite for Postgres, in-memory stores @@ -348,12 +345,14 @@ packages/tavolo-scopone/ # scopone scientifico game (own pyproject + tests) ├── engine.py # pure scopone scientifico rules ├── errors.py # scopone-specific rule violations └── plugin.py # ScoponeEngine: the GameEngine adapter -src/tavolo/ # tavolo-app: composition root (this pyproject.toml) -├── app.py # session/OIDC/Tortoise/OpenAPI/Platform/DeadlineScheduler mixins -├── config.py # env -> frozen Settings -├── aerich_config.py # aerich CLI configuration -├── logging_config.py # logging setup -└── static.py # SPA shell hosting +packages/tavolo-app/ # deployable app: composition root (own pyproject) + src/tavolo/ + ├── app.py # session/OIDC/Tortoise/OpenAPI/Platform/DeadlineScheduler mixins + ├── config.py # env -> frozen Settings + ├── aerich_config.py # aerich CLI configuration + ├── logging_config.py # logging setup + └── static.py # SPA shell hosting +pyproject.toml # tooling shim: [tool.aerich] + [tool.mypy] for server/ CWD migrations/ # aerich migrations for the platform models tests/ # app integration suite (platform + scopone wired together) ``` diff --git a/server/packages/tavolo-app/README.md b/server/packages/tavolo-app/README.md new file mode 100644 index 0000000..2b3fc34 --- /dev/null +++ b/server/packages/tavolo-app/README.md @@ -0,0 +1,31 @@ +# tavolo-app + +The deployable tavolo application: the composition root wiring +[`tavolo-platform`](../tavolo-platform/README.md) to the +[`tavolo-scopone`](../tavolo-scopone/README.md) game. + +## Contents + +- `app.py` — assembles the `KayaApp` (session/OIDC/Tortoise/OpenAPI + mixins plus `PlatformMixin` and the deadline scheduler), registers the + `ScoponeEngine` with its configured timeouts, and exposes + `tavolo.app:app` for granian. +- `config.py` — environment-driven frozen `Settings`. +- `aerich_config.py` — Tortoise ORM configuration consumed by the aerich + CLI (migrations live in `server/migrations/`; aerich itself is + configured via the `[tool.aerich]` section of `server/pyproject.toml`). +- `logging_config.py` — logging setup. +- `static.py` — SPA shell hosting for the compiled frontend. + +## Development (from `packages/tavolo-app/`) + +```sh +.venv/bin/python -m mypy --namespace-packages --explicit-package-bases \ + src/tavolo/app.py \ + src/tavolo/config.py \ + src/tavolo/static.py \ + src/tavolo/aerich_config.py \ + src/tavolo/logging_config.py +``` + +End-to-end coverage of the wired stack lives in `server/tests/`. diff --git a/server/packages/tavolo-app/pyproject.toml b/server/packages/tavolo-app/pyproject.toml new file mode 100644 index 0000000..e9b624b --- /dev/null +++ b/server/packages/tavolo-app/pyproject.toml @@ -0,0 +1,47 @@ +[build-system] +requires = ["setuptools>=68"] +build-backend = "setuptools.build_meta" + +[project] +name = "tavolo-app" +version = "0.1.0" +description = "Tavolo multiplayer card-game application: platform + scopone game wiring" +readme = "README.md" +requires-python = ">=3.10" +dependencies = [ + "tavolo-platform", + "tavolo-scopone", + "kaya-core", + "kaya-cors", + "kaya-session", + "kaya-session-redis", + "kaya-oidc", + "kaya-openapi", + "kaya-rsgi", + "granian>=2.0", + "asyncpg", + "aerich", + "httpx", + "PyJWT[crypto]", + "pwo", + "PyYAML", + "redis", +] + +[project.optional-dependencies] +dev = [ + "mypy", + "httpx-ws", +] +otel = [ + "kaya-otel>=0.0.4", +] + +[tool.setuptools.packages.find] +where = ["src"] +namespaces = true + +[tool.mypy] +python_version = "3.12" +ignore_missing_imports = true +plugins = [] diff --git a/server/src/tavolo/aerich_config.py b/server/packages/tavolo-app/src/tavolo/aerich_config.py similarity index 100% rename from server/src/tavolo/aerich_config.py rename to server/packages/tavolo-app/src/tavolo/aerich_config.py diff --git a/server/src/tavolo/app.py b/server/packages/tavolo-app/src/tavolo/app.py similarity index 100% rename from server/src/tavolo/app.py rename to server/packages/tavolo-app/src/tavolo/app.py diff --git a/server/src/tavolo/config.py b/server/packages/tavolo-app/src/tavolo/config.py similarity index 100% rename from server/src/tavolo/config.py rename to server/packages/tavolo-app/src/tavolo/config.py diff --git a/server/src/tavolo/logging_config.py b/server/packages/tavolo-app/src/tavolo/logging_config.py similarity index 100% rename from server/src/tavolo/logging_config.py rename to server/packages/tavolo-app/src/tavolo/logging_config.py diff --git a/server/src/tavolo/static.py b/server/packages/tavolo-app/src/tavolo/static.py similarity index 100% rename from server/src/tavolo/static.py rename to server/packages/tavolo-app/src/tavolo/static.py diff --git a/server/pyproject.toml b/server/pyproject.toml index a762017..405d6bb 100644 --- a/server/pyproject.toml +++ b/server/pyproject.toml @@ -1,47 +1,11 @@ -[build-system] -requires = ["setuptools>=68"] -build-backend = "setuptools.build_meta" - -[project] -name = "tavolo-app" -version = "0.1.0" -description = "Tavolo multiplayer card-game application: platform + scopone game wiring" -readme = "README.md" -requires-python = ">=3.10" -dependencies = [ - "tavolo-platform", - "tavolo-scopone", - "kaya-core", - "kaya-cors", - "kaya-session", - "kaya-session-redis", - "kaya-oidc", - "kaya-openapi", - "kaya-rsgi", - "granian>=2.0", - "asyncpg", - "aerich", - "httpx", - "PyJWT[crypto]", - "pwo", - "PyYAML", - "redis", -] - -[project.optional-dependencies] -dev = [ - "mypy", - "httpx-ws", -] -otel = [ - "kaya-otel>=0.0.4", -] - -[tool.setuptools.packages.find] -where = ["src"] -namespaces = true - -# Database migrations (aerich). See the Migrations section in README.md. +# NOTE: the tavolo-app distribution lives in packages/tavolo-app/ (same +# kaya-style layout as tavolo-platform and tavolo-scopone). This file +# exists only for tooling that reads configuration from the working +# directory: +# - aerich reads [tool.aerich] from here (server/ locally, /app in the +# db-migrate compose service), next to ./migrations; +# - mypy reads [tool.mypy] from here when run from server/. +# See the Migrations section in README.md. [tool.aerich] tortoise_orm = "tavolo.aerich_config.TORTOISE_ORM" location = "./migrations" diff --git a/server/requirements.txt b/server/requirements.txt index 7fd6756..593c1e3 100644 --- a/server/requirements.txt +++ b/server/requirements.txt @@ -4,11 +4,12 @@ # # pip-compile --allow-unsafe --extra-index-url=https://pypi.org/simple --index-url=https://gitea.woggioni.net/api/packages/woggioni/pypi/simple --output-file=requirements.txt pyproject.toml # -# NOTE: the tavolo-platform and tavolo-scopone sibling packages are NOT -# pinned here: they are installed from ./packages in the Dockerfile and in -# development (pip install -e ./packages/* -e .). All of their third-party -# dependencies are direct dependencies of tavolo-app, so this lock covers -# the full closure. +# NOTE: the tavolo-platform, tavolo-scopone and tavolo-app sibling packages +# are NOT pinned here: they are installed from ./packages in the Dockerfile +# and in development (pip install -e ./packages/tavolo-platform +# -e ./packages/tavolo-scopone -e ./packages/tavolo-app). All of their +# third-party dependencies are direct dependencies of tavolo-app, so this +# lock covers the full closure. # --index-url https://gitea.woggioni.net/api/packages/woggioni/pypi/simple --extra-index-url https://pypi.org/simple