55e5e0153ff3e8256d55dd79f8ecdb5e46d3ffe7
3 Commits
| Author | SHA1 | Message | Date | |
|---|---|---|---|---|
|
|
55e5e0153f |
feat(production): dai una vita propria alla produzione, lato server
Punto 1 del documento modifiche del 28/07, il prerequisito su cui poggiano i punti 3, 4 e 6. Lo stato di una produzione viveva dentro una pagina del browser: timer, conteggio cicli e flag "produzione avviata" erano variabili Alpine di task_execute.html, e la navigazione fra task e' un ricaricamento completo, quindi cambiando task si perdeva tutto. Da qui il loop di misura che non reggeva, il fermo linea che non aveva nulla da fermare e l'assenza di storico. Nuove tabelle production_runs e production_events (migrazione 005), endpoint REST senza stato in memoria di processo - con un'app di stazione installata su ogni PC il database e' l'unico posto condiviso - e il frontend che legge lo stato all'apertura invece di tenerlo in memoria. Tre scelte di modello: - la scadenza e' un timestamp assoluto (next_measurement_at), non un contatore: il countdown si ricalcola da li' a ogni caricamento, e lasciarne andare la differenza sotto zero dara' gratis il contatore del ritardo del punto 3. Al client vanno i secondi gia' calcolati, non il timestamp: un datetime naive verrebbe letto nel fuso del browser e il conto sarebbe sfasato dell'offset UTC; - l'intervallo di misura e' copiato sulla produzione, non referenziato: modificare la ricetta a produzione avviata non deve spostare una scadenza in corso; - active_station_id rispecchia la stazione finche' la produzione e' aperta e va a NULL alla chiusura. Con un vincolo unico sopra, "una stazione = una produzione aperta" e' una garanzia del database e non un controllo soggetto a race; i NULL non collidono, quindi le produzioni chiuse si accumulano senza disturbo. Il fermo linea congela il conto alla rovescia e alla ripresa la scadenza viene traslata della durata del fermo, non ricalcolata: un fermo non regala ne' toglie tempo all'operatore. L'autorizzazione del capoturno passa da authenticate_user e non da un login, che rigenererebbe la sua API key buttando giu' la sessione che ha aperta altrove. La migrazione e' stata eseguita davvero, non solo scritta, su uno SQLite usa e getta: upgrade e downgrade girano e le colonne coincidono con i modelli. La prova ha trovato un difetto - create_unique_constraint dopo create_table e' un ALTER, che SQLite rifiuta - ora il vincolo e' dichiarato dentro create_table. Fuori da questo commit, per stare nei confini del punto 1: l'API espone gia' pause, resume e close, ma i pulsanti fermo linea e fine produzione restano da collegare (punto 6), e il rientro forzato sulla misura allo scadere e' il punto 3. Corretti due difetti trovati strada facendo: env.py non importava ne' Station ne' ProductionRun, quindi l'autogenerate di Alembic era gia' cieco sulle stazioni; e task_execute.html, lo schermo con piu' JavaScript dell'applicazione, non era coperto dal test di sintassi. Aggiungerlo ha richiesto di correggere l'helper, che validava le espressioni Alpine solo come espressione singola e bocciava @click="a = false; b = true", forma che Alpine accetta: ora prova entrambe le letture e fallisce solo se cadono tutte e due. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> |
||
|
|
742cc1fb58 |
fix(v2): two regressions surfaced by the local smoke test
Both came from the src/ restructure and only show up at runtime, so
the test suite had not caught them.
- src/backend/config.py: env_file was "../../.env", which pydantic-
settings resolves against the *cwd*, not the file. Running uvicorn
or alembic from the project root therefore looked for
../../.env one level above the repo and silently fell back to the
default DB_PASSWORD ("change_me_in_production"), hiding the real
password. Now resolved as Path(__file__).resolve().parents[2] /
".env" so the lookup is always against the project root regardless
of cwd.
- src/backend/models/orm/__init__.py: Station and
StationRecipeAssignment were never imported here, so anything that
triggers Base.metadata.create_all without first importing the
setup router (which has its own Station import) ended up with no
stations / station_recipe_assignments tables. Verified locally:
/api/setup/seed used to fail with "Table tiemeasureflow.stations
doesn't exist" before this fix.
- .gitignore: ignore src/frontend/flask_app/package.json and
package-lock.json (local npm-install artifacts; the Dockerfile
installs tailwindcss directly).
Smoke verified end-to-end: uvicorn + gunicorn + MySQL, login + admin
stations + select_recipe + admin users all 200 OK.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
|
||
|
|
1a0431366f |
chore(v2): restructure monorepo to src/ layout with uv
Aligns the repo with the python-project-spec-design.md template chosen for V2.0.0. Big move, no logic changes. The 3 pre-existing test failures (test_recipes::test_update_recipe, test_recipes:: test_recipe_versioning, test_tasks::test_reorder_tasks, plus the client test_save_measurement_proxy) survive unchanged. Layout changes - server/ -> src/backend/ - server/middleware/ -> src/backend/api/middleware/ - server/routers/ -> src/backend/api/routers/ - server/models/ -> src/backend/models/orm/ - server/schemas/ -> src/backend/models/api/ - server/uploads/ -> uploads/ (project root, mounted volume) - server/tests/ -> src/backend/tests/ - client/ -> src/frontend/flask_app/ (Flask kept; React deroga is documented in CLAUDE.md, justified by tablet UX, USB caliper/barcode workflow and Fabric.js integration) Tooling - pyproject.toml: monorepo with [project] core deps and optional-dependencies server / client / dev. Replaces both server/requirements.txt and client/requirements.txt. - uv.lock + .python-version (3.11) committed for reproducible builds. - Dockerfile (root, backend) and Dockerfile.frontend rewritten to use uv sync --frozen --no-dev --extra server|client; legacy Dockerfiles preserved as Dockerfile.legacy for reference but excluded from build context via .dockerignore. - docker-compose.dev.yml + docker-compose.yml: build context now ".", dockerfile pointing to the root files. Code adjustments forced by the move - Every "from config|database|models|schemas|services|routers|middleware import ..." rewritten to its src.backend.* equivalent (50+ files including indented inline imports inside test bodies). - src/backend/migrations/env.py: insert project root into sys.path so alembic can resolve src.backend.* imports regardless of cwd. - src/backend/config.py: env_file ../../.env (was ../.env), upload_path resolves project root via parents[2]. - src/backend/tests/conftest.py + tests: import ... from src.backend.* instead of bare names; old per-directory pytest.ini files removed in favor of root pyproject.toml [tool.pytest.ini_options]. - .gitignore: uploads/ at root, src/frontend/flask_app/static/css/ tailwind.css path; .dockerignore tightened. - CLAUDE.md: rewrote sections "Layout del repository", "Comandi di Sviluppo", "Database & Migrations", "Test", "i18n", and all path references throughout the architecture sections. Verified - uv lock resolves 77 packages; uv sync --extra server --extra client --extra dev installs cleanly. - uv run pytest: 171 passed, 4 pre-existing failures. - uv run alembic -c src/backend/migrations/alembic.ini check loads config and metadata (errors only on the absent local MySQL). Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> |