Files
crr-tools/migration/README.md
T
jfmcarreira 561b6a2da9
App checks / changes (push) Canceled after 0s
App checks / tournament (push) Canceled after 0s
App checks / shifts (push) Canceled after 0s
feat: monorepo migration phase 3
2026-10-07 11:38:43 +01:00

240 lines
14 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# Migration progress
Verified on 2026-10-07. Follow `MONOREPO_MIGRATION_PLAN.md`; its historical source
labels resolve to `originals/tournment-manager-web/` and `originals/crr-shifts/`.
## Phase 0 — behaviour baseline: complete
Both untouched source snapshots were copied into disposable `.migration/`
directories before dependency installation, tests and builds. SHA-256 manifests
confirm that source files match the snapshots after the checks and app copies.
No commands installed dependencies or generated outputs inside `originals/`.
| Baseline check | Result |
| --- | --- |
| Tournament `npm test` | 55 passed, 8 files |
| Tournament `npm run typecheck` | Passed |
| Tournament `npm run build` | Vue and server builds passed |
| Shifts pytest, Python 3.13.13 | 14 passed |
| Tournament SQLite integrity / foreign keys | Passed |
| Desktop/mobile screenshots | 14 captured, including print cards |
Tournament was checked locally using Node 26.0.0/npm 11.12.1, satisfying the
legacy `>=22` engine constraint. Node 22 remains the CI/container target; its CI
checks have not run yet. The legacy package has no `lint` script. Shifts' legacy
requirements resolve the same versions as the new root lockfile's runtime/test
dependencies. Existing upstream/runtime deprecation warnings remain visible.
### Preserved evidence
- `baseline/tournament.json` and `baseline/shifts.json`: source checksums,
executed commands, exit codes and individual passing test names.
- `baseline/artifacts.json`: fixture and screenshot checksums.
- `fixtures/tournament.sqlite`: database created by the actual legacy Node
application, containing all nine existing tables and no Alembic stamp.
- `fixtures/tournament-schema.json` and `tournament-rows.json`: exact legacy
schema/index definitions and persisted contents for adoption checks.
- `fixtures/tournament-state.json`: expected public state, including standings,
final-stage results, champion and third-place match.
- `fixtures/tournament-api.json`: observable requests/statuses/bodies for a
synthetic workflow, authentication failures, duplicate-number conflict and 404.
- `fixtures/tournament-routes.json`: explicit API method/path inventory. This is
an inventory, not a substitute for the legacy integration suite.
- `fixtures/tournament-cookie.json`: cookie attributes with its token removed.
- `screenshots/`: desktop (1440×1000), mobile (390×844), login/results/admin pages
and Tournament match cards in print media, with a capture manifest.
Fixtures contain synthetic Portuguese names and public test-only credentials;
they contain no production data. Timestamps in the final Tournament database
are fixed; the browser clock is fixed for screenshots. Shifts demo schedules
use the server's capture month, October 2026. Raw execution logs and test-runner
reports remain available locally under ignored `migration/results/`.
### Reproduce
```sh
make baseline-test
make baseline-fixtures
make baseline-screenshots
make baseline-preserve
```
These commands require Node 22+, Python 3.13, uv, and Playwright's Chromium
download for screenshot capture. `baseline-test` replaces disposable staging
copies. Fixture/screenshot capture intentionally refreshes migration artefacts.
It starts isolated servers on localhost ports 18080 and 18081 and shuts them
down afterwards. Run screenshot commands serially. Repeated captures in a
different month/browser version may need a reviewed visual baseline update.
This machine's `uv` is installed through the Python 3.14.6 pyenv environment,
while `.python-version` selects 3.13. Commands here used
`PYENV_VERSION=3.14.6 make shifts-test` (and that environment for baseline tooling)
to resolve the uv executable; uv still used Python 3.13.13 for Shifts. Other
machines with uv available independently do not need that override.
## Phase 1 — monorepo paths: local exit verified; remote CI pending
- Tournament source/lockfile copied into `apps/tournament/`, retaining its
working `src/{client,server,shared}` layout during this phase.
- Shifts app/templates/static files, tests and unchanged migration history copied
into `apps/shifts/backend/`; domain/architecture reference docs copied too.
- Root uv workspace, Python 3.13 constraint, single lockfile and independent
Shifts project metadata added. Tournament enters the workspace in Phase 3.
- Root namespaced Makefile commands, Python configuration, app instructions and
development documentation added.
- Independent root-context Dockerfiles and Compose services/volumes added.
Optional per-app environment files let either service be configured separately.
- Path-filtered CI tests/builds only affected apps; shared branding/Python/root
tooling changes trigger both as applicable. No production or CI job runs from
`originals/`.
| Migrated check | Result |
| --- | --- |
| `make tournament-test` | 55 tests and both typechecks passed |
| `make tournament-build` | Vue and server builds passed |
| `make shifts-test` | 14 passed with locked Python 3.13 dependencies |
| Live app rendering from `apps/` | Both applications served successfully |
| `make migration-visual-check` | All 14 captures byte-for-byte match legacy |
| `docker compose config --quiet` | Passed; both independent services listed |
| Docker image builds | Both passed: Tournament Node 22, Shifts Python 3.13 |
| `make images-smoke-test` | Both containers started; JSON/HTML routes passed |
| GitHub Actions | Workflow added; remote execution not verified |
`tools/migrate_app_sources.py` was used for the one-time source copy. It refuses
existing destinations rather than overwriting application work. Do not rerun it
against the populated apps. Requirements files stay in the migrated Shifts copy
until the lockfile workflow passes CI, as required by the plan.
Docker was initially stopped; Docker Desktop was started and both independent
image builds then passed. The smoke check used temporary containers, random
localhost ports, synthetic credentials and tmpfs databases; containers were
removed after checking Tournament `/api/public/state` and `/results`, and Shifts
`/health` and `/login`. No production database or persistent volume was used.
Repeat image checks after building both images:
```sh
docker build -f apps/tournament/Dockerfile -t crr-tournament .
make shifts-build
make images-smoke-test
```
## Phase 2 — shared CRR brand: locally verified complete
- Created `packages/crr-brand` with one canonical Tournament logo (2324×2051)
and favicon, copied byte-for-byte from the baseline. Shared CSS defines the
red `#ed1c24` palette, neutral/control/error colors, font stack, radii, shadows
and spacing tokens, plus common base, button, panel and error-alert rules.
- Both apps load tokens/base/components before app styles. Existing variable
names now alias shared tokens. Responsive layouts, typography hierarchy,
control padding, specialist badges and print-card dimensions stay app-local.
- Tournament imports the package through Vite's `@crr-brand` alias and public
asset directory; shared files also work in Vite development under `/jogo/`.
- Shifts mounts `/brand`, generates prefixed asset URLs through Jinja `url_for`,
and uses the canonical logo in PDF exports. Its login logo retains the old
display aspect ratio to avoid a subpixel form-layout shift from the source
image's slightly different dimensions.
- Removed the two app-local logo files and Tournament's local favicon after
successful visual verification. Original snapshots remain unchanged.
- Both root-context images consume the package; the existing brand path filter
triggers both application CI jobs.
| Check | Result |
| --- | --- |
| Tournament tests/typechecks | 55 passed; both typechecks passed |
| Tournament Vue/server build | Passed |
| Shifts tests, including PDF exports and brand resources | 16 passed |
| Shifts brand assets under `/` and `/crr` | CSS, logo and favicon passed |
| Tournament Vite development under `/jogo/` | Page, favicon, entrypoint, shared CSS and logo passed |
| `make branding-visual-check` | All 14 captures preserve measured legacy element rectangles exactly |
| Tournament print cards | Both desktop/mobile captures match Phase 0 byte-for-byte |
| `make migration-visual-check` | All 14 captures match the new Phase 2 reference byte-for-byte |
| Both Docker builds | Passed |
| `make images-smoke-test` | Both containers serve HTML/JSON and referenced CSS/JS/PNG resources |
Visual review confirmed the intended palette/control-focus/panel-corner changes
and sharper canonical Shifts logo, with no layout regressions in the captured
desktop/mobile pages. `phase2/screenshots/` preserves the 14 updated PNGs,
capture manifest and measured rectangles. `phase2/verification.json` records
the geometry/print results, element counts and screenshot checksums. Phase 0
screenshots and compatibility fixtures are retained unchanged.
`make branding-visual-check` compares geometry against new captures of the
isolated legacy copies, allowing the deliberate color/asset changes. Future
`make migration-visual-check` runs use `phase2/screenshots/` as their exact
reference. Both require the Phase 0 staging/Playwright setup described above.
Container smoke checks emulate the existing Tournament proxy's `/jogo` prefix
stripping when fetching its built asset URLs. Remote CI remains unverified.
## Phase 3 — Tournament FastAPI replacement: locally verified complete
- Added the independent `crr-tournament` Python 3.13 workspace member, version
1.0.0, with FastAPI, SQLAlchemy 2, Alembic and Pydantic Settings.
- Modeled the nine existing SQLite tables with typed `Mapped` columns. The frozen
Alembic baseline creates the exact Node schema and defaults. Existing databases
are validated before stamping, including column types/nullability, defaults,
primary/unique keys, checks, indexes, foreign keys, autoincrement and group
collation. Validation/stamping/upgrades use an explicit SQLite transaction;
failed upgrades roll back schema creation. Foreign keys/WAL/5000 ms timeout
apply to every connection.
- Ported calendar generation, standard/total-points standings and head-to-head
tie breakers, brackets/byes/third-place advancement, seeding and state assembly.
- Added domain-grouped request/response schemas and separate auth/public/admin
routers. CamelCase payloads, status/error shapes, Portuguese messages, HTTP
methods and confirmation rules are preserved. Request validation also covers
JavaScript-style ID coercion, name trimming and UTF-16 length limits.
- Reproduced the Node HMAC-SHA256/base64url session format and cookie semantics;
verified a token produced by the actual Node implementation. Preserved the
five-failure/15-minute login window and successful-login reset. Synchronization
preserves serial numbering and atomic login limiting under ASGI concurrency.
- Ported notification-only SSE with retry 3000, 25-second heartbeat, exact
state-change frames and subscriber cleanup. FastAPI serves the existing Vue
build, including the legacy sub-path proxy deployment behavior.
- Switched development and production runtime to Uvicorn/Python. The image builds
Vue with Node 22 and preserves UID/GID 1000 for existing SQLite volumes. Removed
Fastify, better-sqlite3, Zod, tsx and backend-only type packages/scripts from
the frontend dependency graph after compatibility checks passed.
- Updated Makefile/CI to check both Python and frontend code. Preserved all 44
legacy HTTP/service assertions under `contracts/` and execute them unchanged
using migration-only Python transports. This compatibility command uses owned
contracts and app tooling; CI never reads/builds/runs `originals/`.
| Check | Result |
| --- | --- |
| Backend pytest | 28 passed |
| Preserved legacy assertions against Python | 44 passed: 19 HTTP/SSE, 25 deterministic services |
| Frontend/shared tests | 13 passed |
| Vue typecheck and build | Passed |
| Fresh database schema/defaults vs Node | Exact normalized SQLite DDL match |
| Python startup with populated Node fixture | All nine table contents and public state preserved |
| Incompatible schemas / migration failure | Refused without stamping; failed DDL rolled back |
| Token compatibility / cookies / limiter | Node-produced token and HTTPS/proxy/window/reset/concurrency checks passed |
| `make migration-visual-check` | All 14 screenshots match Phase 2 byte-for-byte |
| Both Docker builds | Passed |
| Container smoke checks | Fresh Tournament, adopted Node fixture and Shifts passed; referenced resources served |
| Shifts regression suite | 16 passed |
`phase3/compatibility.json` preserves passing legacy test names and contract
checksums; raw test reports remain in `.migration/port-compat/`. Database tests
copy the Node fixture before adoption; container adoption checks likewise use a
read-only fixture mount copied into tmpfs. No production database was used.
The TypeScript server source/config files are retired reference material pending
Phase 6 cleanup; production images contain only the Python backend and built
Vue assets. The Vue source directory move is also deferred to that cleanup.
Compatibility transport scaffolding remains until the corresponding cleanup
exit criteria are verified. Remote GitHub Actions execution is still unverified.
On this machine, the pyenv override described above also applies to Tournament
Makefile commands; uv still executes the applications on Python 3.13.
## Next work
1. Verify the new CI jobs on Node 22/Python 3.13 after publishing the changes.
2. Phase 4: Shifts service/model/security extraction and router split, preserving
routes, templates, forms, authentication, SQLite data and migration history.
Phases 4–6 are not complete. No shared Python package has been extracted yet.
Independent tag-triggered release workflows and final dependency cleanup belong
to later phases.