Move tavolo-app under packages/ for a uniform monorepo layout
CI / Build and push docker image (push) Successful in 2m29s

Relocate the composition root (app, config, static, logging_config,
aerich_config) from server/src/tavolo/ to
packages/tavolo-app/src/tavolo/, with its own pyproject.toml and README
like the sibling distributions. Module paths and the granian entrypoint
are unchanged.

server/pyproject.toml remains as a tooling shim ([tool.aerich] next to
./migrations, [tool.mypy] for runs from server/); the Dockerfile installs
all three distributions from ./packages. Verified: all suites green,
mypy clean per package, aerich resolves the moved config identically,
wheel builds.
This commit is contained in:
2026-09-21 13:04:09 +08:00
parent 83ecf9bed3
commit 2b738ea2fe
12 changed files with 112 additions and 68 deletions
+1 -1
View File
@@ -56,7 +56,7 @@ Backend (from `server/`):
cd server cd server
python3 -m venv .venv python3 -m venv .venv
.venv/bin/pip install -r requirements.txt .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 tests -t .
.venv/bin/python -m unittest discover -s packages/tavolo-platform/tests .venv/bin/python -m unittest discover -s packages/tavolo-platform/tests
.venv/bin/python -m unittest discover -s packages/tavolo-scopone/tests .venv/bin/python -m unittest discover -s packages/tavolo-scopone/tests
+8 -6
View File
@@ -55,14 +55,16 @@ RUN --mount=type=cache,target=/root/.cache/pip \
&& /opt/venv/bin/pip install --upgrade pip \ && /opt/venv/bin/pip install --upgrade pip \
&& /opt/venv/bin/pip install -r requirements.txt && /opt/venv/bin/pip install -r requirements.txt
COPY server/pyproject.toml server/README.md ./ # The three sibling distributions, installed from the local tree (PEP 420
COPY server/src/ ./src/ # namespace packages sharing the `tavolo` namespace). --no-deps: every
# Sibling distributions, installed from the local tree (PEP 420 namespace # third-party dependency is already pinned in requirements.txt.
# packages sharing the `tavolo` namespace with the app above). --no-deps:
# every third-party dependency is already pinned in requirements.txt.
COPY server/packages/ ./packages/ COPY server/packages/ ./packages/
RUN --mount=type=cache,target=/root/.cache/pip \ 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 # aerich migration files are a release artifact: the db-migrate compose
# service runs `aerich upgrade` from this image before the app starts. # service runs `aerich upgrade` from this image before the app starts.
COPY server/migrations/ ./migrations/ COPY server/migrations/ ./migrations/
+11 -12
View File
@@ -13,7 +13,7 @@ and [`packages/tavolo-scopone/README.md`](packages/tavolo-scopone/README.md)):
- **`tavolo-scopone`** (`packages/tavolo-scopone/`) — scopone - **`tavolo-scopone`** (`packages/tavolo-scopone/`) — scopone
scientifico, the four-player, fixed-partnership variant of the classic scientifico, the four-player, fixed-partnership variant of the classic
Italian card game: pure rules plus the platform adapter. 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 composition root wiring the platform to the scopone game, with the
environment-driven settings and the SPA shell. environment-driven settings and the SPA shell.
@@ -279,18 +279,15 @@ must dismiss. A play attempted in this phase is rejected with an
```sh ```sh
python3 -m venv .venv python3 -m venv .venv
.venv/bin/pip install -r requirements.txt .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: # app integration suite:
.venv/bin/python -m unittest discover -s tests -t . .venv/bin/python -m unittest discover -s tests -t .
# per-package suites (each package is self-contained): # 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-platform/tests
.venv/bin/python -m unittest discover -s packages/tavolo-scopone/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.platform
.venv/bin/python -m mypy -p tavolo.scopone .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 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 ├── engine.py # pure scopone scientifico rules
├── errors.py # scopone-specific rule violations ├── errors.py # scopone-specific rule violations
└── plugin.py # ScoponeEngine: the GameEngine adapter └── plugin.py # ScoponeEngine: the GameEngine adapter
src/tavolo/ # tavolo-app: composition root (this pyproject.toml) packages/tavolo-app/ # deployable app: composition root (own pyproject)
├── app.py # session/OIDC/Tortoise/OpenAPI/Platform/DeadlineScheduler mixins src/tavolo/
├── config.py # env -> frozen Settings ├── app.py # session/OIDC/Tortoise/OpenAPI/Platform/DeadlineScheduler mixins
├── aerich_config.py # aerich CLI configuration ├── config.py # env -> frozen Settings
├── logging_config.py # logging setup ├── aerich_config.py # aerich CLI configuration
└── static.py # SPA shell hosting ├── 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 migrations/ # aerich migrations for the platform models
tests/ # app integration suite (platform + scopone wired together) tests/ # app integration suite (platform + scopone wired together)
``` ```
+31
View File
@@ -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/`.
+47
View File
@@ -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 = []
+8 -44
View File
@@ -1,47 +1,11 @@
[build-system] # NOTE: the tavolo-app distribution lives in packages/tavolo-app/ (same
requires = ["setuptools>=68"] # kaya-style layout as tavolo-platform and tavolo-scopone). This file
build-backend = "setuptools.build_meta" # exists only for tooling that reads configuration from the working
# directory:
[project] # - aerich reads [tool.aerich] from here (server/ locally, /app in the
name = "tavolo-app" # db-migrate compose service), next to ./migrations;
version = "0.1.0" # - mypy reads [tool.mypy] from here when run from server/.
description = "Tavolo multiplayer card-game application: platform + scopone game wiring" # See the Migrations section in README.md.
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.
[tool.aerich] [tool.aerich]
tortoise_orm = "tavolo.aerich_config.TORTOISE_ORM" tortoise_orm = "tavolo.aerich_config.TORTOISE_ORM"
location = "./migrations" location = "./migrations"
+6 -5
View File
@@ -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 # 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 # NOTE: the tavolo-platform, tavolo-scopone and tavolo-app sibling packages
# pinned here: they are installed from ./packages in the Dockerfile and in # are NOT pinned here: they are installed from ./packages in the Dockerfile
# development (pip install -e ./packages/* -e .). All of their third-party # and in development (pip install -e ./packages/tavolo-platform
# dependencies are direct dependencies of tavolo-app, so this lock covers # -e ./packages/tavolo-scopone -e ./packages/tavolo-app). All of their
# the full closure. # 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 --index-url https://gitea.woggioni.net/api/packages/woggioni/pypi/simple
--extra-index-url https://pypi.org/simple --extra-index-url https://pypi.org/simple