432 lines
14 KiB
Markdown
432 lines
14 KiB
Markdown
# RollCalcPython
|
||
|
||
Flask-based internal roll diameter calculator for Naue roll products. The app is a small authenticated Flask shell around a mostly client-side calculator UI.
|
||
|
||
This README is intended for developers maintaining the project, not for end users.
|
||
|
||
## Runtime Stack
|
||
|
||
- Python 3
|
||
- Flask 2.3.3
|
||
- Flask-HTTPAuth 4.8.0
|
||
- markdown-it-py 3.0.0 for server-side Markdown rendering
|
||
- Vanilla HTML, CSS, and JavaScript
|
||
- JSON files for product data and forklift/load rules
|
||
|
||
Pinned Python dependencies are defined in `requirements.txt`.
|
||
|
||
## Local Setup
|
||
|
||
Create and activate a virtual environment:
|
||
|
||
```bash
|
||
python3 -m venv .venv
|
||
source .venv/bin/activate
|
||
pip install -r requirements.txt
|
||
```
|
||
|
||
Start with the hardcoded settings in `app.py`:
|
||
|
||
```bash
|
||
python app.py
|
||
```
|
||
|
||
By default this attempts to bind to:
|
||
|
||
```text
|
||
http://localhost:5000
|
||
```
|
||
|
||
If port `5000` is already occupied, start through Flask's CLI without changing files:
|
||
|
||
```bash
|
||
flask --app app run --host 127.0.0.1 --port 5001
|
||
```
|
||
|
||
The app uses HTTP Basic Auth. Current users are defined in a local deployment file, `config/users.json`, with Werkzeug password hashes. This file is intentionally not versioned.
|
||
|
||
## Project Layout
|
||
|
||
```text
|
||
.
|
||
├── app.py
|
||
├── requirements.txt
|
||
├── README.md
|
||
├── build_info.json
|
||
├── access_log.json
|
||
├── config.json
|
||
├── article-data_.json
|
||
├── fix_article_data.py
|
||
├── service-worker.js
|
||
├── templates/
|
||
│ ├── help_index.html
|
||
│ ├── roll_calculator.html
|
||
│ └── user_manual.html
|
||
├── static/
|
||
│ ├── article-data.json
|
||
│ ├── config.json
|
||
│ ├── service-worker.js
|
||
│ ├── stddev_calculator.js
|
||
│ ├── direct_calc_handler.js
|
||
│ ├── rollcalc_v14.js
|
||
│ ├── rollcalc_improvements.js
|
||
│ ├── rollcalc-improvements.js
|
||
│ ├── rollcalc_stddev_ranges.js
|
||
│ └── rollcalc_stddev_integration.js
|
||
└── docs/
|
||
├── de/
|
||
│ ├── screenshots/
|
||
│ └── user_manual.md
|
||
├── DEPLOYMENT_GUIDE.md
|
||
├── QOL_UPDATE_SUMMARY.md
|
||
├── STDDEV_IMPLEMENTATION_CHECKLIST.md
|
||
└── STDDEV_RANGES_DOCS.md
|
||
```
|
||
|
||
## Backend
|
||
|
||
`app.py` owns the Flask application and authentication.
|
||
|
||
Implemented routes:
|
||
|
||
| Route | Methods | Auth | Purpose |
|
||
| --- | --- | --- | --- |
|
||
| `/` | `GET` | Basic Auth | Renders `templates/roll_calculator.html`. |
|
||
| `/help` | `GET` | Basic Auth | Renders the Help landing page. |
|
||
| `/help/user-manual` | `GET` | Basic Auth | Reads `docs/de/user_manual.md`, renders it as HTML, and displays it in the RollCalc Help layout. |
|
||
| `/help/recent-changes` | `GET` | Basic Auth | Reads `docs/de/recent_changes.md`, renders it as HTML, and displays it in the RollCalc Help layout. |
|
||
| `/help/user-manual/screenshots/<path:filename>` | `GET` | Basic Auth | Serves German user-manual screenshots from `docs/de/screenshots/` only. |
|
||
| `/static/<path:filename>` | `GET` | Basic Auth | Intended protected static-file serving from `static/`. |
|
||
| `/api/health` | `GET` | Basic Auth | Returns app health and version. |
|
||
| `/api/user` | `GET` | Basic Auth | Returns current authenticated user info. |
|
||
|
||
Authentication is implemented with `Flask-HTTPAuth`. The current code loads the local `config/users.json` deployment file and checks password hashes with `werkzeug.security.check_password_hash`; plaintext passwords are not stored in the application.
|
||
|
||
## User Management
|
||
|
||
Manage users with the interactive CLI:
|
||
|
||
```bash
|
||
python3 scripts/manage_users.py
|
||
```
|
||
|
||
The menu supports:
|
||
|
||
- List users
|
||
- Create user
|
||
- Change password
|
||
- Delete user
|
||
|
||
User data is stored in:
|
||
|
||
```text
|
||
config/users.json
|
||
```
|
||
|
||
`config/users.json` is local deployment data and is ignored by Git. The versioned file `config/users.example.json` documents the format only and must not contain real usernames, hashes, or passwords.
|
||
|
||
The file contains only username-to-password-hash mappings:
|
||
|
||
```json
|
||
{
|
||
"username": "<hash>"
|
||
}
|
||
```
|
||
|
||
Passwords are entered with `getpass`, are never echoed, and are never stored in plaintext. New and changed passwords use the existing RollCalc hash method:
|
||
|
||
```text
|
||
pbkdf2:sha256:600000
|
||
```
|
||
|
||
Do not commit real passwords or print them in logs.
|
||
|
||
On a server, ensure that the process running RollCalc can read `config/users.json`. A suitable deployment setup can be:
|
||
|
||
```text
|
||
owner: martin
|
||
group: www-data
|
||
mode: 640
|
||
```
|
||
|
||
The exact owner and group depend on the deployment. Do not hard-code them in the application. Before deploying or replacing a server instance, back up the productive `config/users.json` file.
|
||
|
||
Access logging is handled by `log_access()`, which reads `access_log.json`, appends a record, and writes the whole file back.
|
||
|
||
## Help and User Manual
|
||
|
||
RollCalc exposes an authenticated Help area at:
|
||
|
||
```text
|
||
/help
|
||
```
|
||
|
||
The user manual is available at:
|
||
|
||
```text
|
||
/help/user-manual
|
||
```
|
||
|
||
Recent changes are available at:
|
||
|
||
```text
|
||
/help/recent-changes
|
||
```
|
||
|
||
`docs/de/user_manual.md` is the leading source for the German user manual. The app reads this Markdown file on request and renders it server-side with `markdown-it-py`; no generated static HTML copy is maintained. Raw HTML in the Markdown source is disabled during rendering.
|
||
|
||
`docs/de/recent_changes.md` is the leading source for full German release notes. It is rendered through the same authenticated Markdown infrastructure.
|
||
|
||
The documentation directory is prepared for additional languages:
|
||
|
||
```text
|
||
docs/
|
||
de/
|
||
user_manual.md
|
||
screenshots/
|
||
```
|
||
|
||
The public route `/help/user-manual` currently opens the German manual. No language switcher is implemented yet.
|
||
|
||
Screenshots referenced from the manual as `screenshots/filename.png` should be placed in:
|
||
|
||
```text
|
||
docs/de/screenshots/
|
||
```
|
||
|
||
The application rewrites those relative Markdown image paths to the authenticated manual screenshot route, which is limited to the active language's screenshot directory.
|
||
|
||
### What's New Dialog
|
||
|
||
The calculator page shows a compact What's New dialog once per build version. The current version comes from `build_info.version`; if that value is empty or `unknown`, the dialog is not shown.
|
||
|
||
The last acknowledged version is stored only in the browser:
|
||
|
||
```text
|
||
rollcalc_last_seen_version
|
||
```
|
||
|
||
The short dialog summary is maintained in:
|
||
|
||
```text
|
||
static/recent_changes.json
|
||
```
|
||
|
||
Keep `docs/de/recent_changes.md` as the complete release-note source and `static/recent_changes.json` as the short 3-5 item summary for the startup dialog.
|
||
|
||
## User Manual PDF Export
|
||
|
||
Generate the current PDF version of the German user manual with:
|
||
|
||
```bash
|
||
./scripts/build_user_manual_pdf.sh
|
||
```
|
||
|
||
The script renders `docs/de/user_manual.md` to `docs/de/user_manual.pdf` with Pandoc. The Markdown file remains the leading source.
|
||
|
||
## Frontend Entry Point
|
||
|
||
The active UI is `templates/roll_calculator.html`.
|
||
|
||
The template contains:
|
||
|
||
- Page layout and all main CSS.
|
||
- A disclaimer modal shown after Basic Auth login and before calculator use.
|
||
- Footer build metadata from `build_info`.
|
||
- Global state:
|
||
- `window.ARTICLE_DATA`
|
||
- `window.APP_CONFIG`
|
||
- Product/article data loading from `/static/article-data.json`.
|
||
- Direct roll calculations.
|
||
- Extrapolation calculations.
|
||
- Forklift/weight warnings.
|
||
- Load optimizer UI and calculations.
|
||
|
||
Most of the currently active JavaScript is inline in this template. Several files under `static/` appear to be older, alternative, or integration-oriented modules and should be checked before assuming they are active.
|
||
|
||
## Main Functional Areas
|
||
|
||
### Disclaimer Gate
|
||
|
||
The calculator page displays a modal disclaimer before use. The modal:
|
||
|
||
- Shows German and English disclaimer text.
|
||
- Requires a checkbox confirmation.
|
||
- Keeps the confirmation button disabled until checked.
|
||
- Hides the overlay after confirmation.
|
||
|
||
This is implemented in `templates/roll_calculator.html` and is client-side only.
|
||
|
||
### Article Data Loading
|
||
|
||
`templates/roll_calculator.html` fetches:
|
||
|
||
```text
|
||
/static/article-data.json
|
||
```
|
||
|
||
The loaded array is assigned to `window.ARTICLE_DATA` and used to populate article datalists for direct calculation and extrapolation.
|
||
|
||
Known article fields used by the UI include:
|
||
|
||
- `nr`
|
||
- `name`
|
||
- `thickness`
|
||
- `thickness_stddev`
|
||
- `area_weight`
|
||
- `area_weight_stddev`
|
||
- `core_type`
|
||
|
||
The active `static/article-data.json` currently contains product records with additional min/max/count statistics.
|
||
|
||
### Direct Calculation
|
||
|
||
The direct calculation tab supports multiple modes via mode buttons:
|
||
|
||
- Roll diameter from core diameter, material thickness, and product length.
|
||
- Product length from core diameter, material thickness, and roll diameter.
|
||
- Product length for a target diameter.
|
||
|
||
The nominal roll diameter formula used in the template is:
|
||
|
||
```text
|
||
D = sqrt(d^2 + (4 * L * 1000 * t) / pi)
|
||
```
|
||
|
||
Where:
|
||
|
||
- `D` is roll diameter in mm.
|
||
- `d` is core diameter in mm.
|
||
- `L` is product length in m.
|
||
- `t` is material thickness in mm.
|
||
|
||
If a tolerance/stddev value is present, the UI also displays a `-2σ` and `+2σ` diameter range.
|
||
|
||
Roll weight is calculated when roll width, area weight, and length are present:
|
||
|
||
```text
|
||
weight_kg = area_weight_g_m2 * length_m * width_m / 1000
|
||
```
|
||
|
||
### Extrapolation
|
||
|
||
The extrapolation tab estimates a new roll diameter from a known roll diameter/length pair and a new target length:
|
||
|
||
```text
|
||
D1 = sqrt(d^2 + (L1 / L0) * (D0^2 - d^2))
|
||
```
|
||
|
||
Where:
|
||
|
||
- `d` is core diameter.
|
||
- `D0` is measured/current diameter.
|
||
- `L0` is measured/current length.
|
||
- `L1` is target length.
|
||
- `D1` is the calculated new diameter.
|
||
|
||
### Forklift Check
|
||
|
||
`checkForklift()` in `templates/roll_calculator.html` evaluates heavy-roll warnings using `window.APP_CONFIG.forklift_rules`.
|
||
|
||
The current inline config targets the `bentofix` category and includes:
|
||
|
||
- Warning threshold: `1700 kg`
|
||
- Hard limit: `2750 kg`
|
||
- Minimum core outer diameter requirement: `170 mm`
|
||
|
||
There is also a richer `static/config.json` with localized messages and more detailed requirements.
|
||
|
||
### Load Optimizer
|
||
|
||
The Load Optimizer is implemented by inline classes in `templates/roll_calculator.html`:
|
||
|
||
- `LoadOptimizer`
|
||
- `LoadOptimizerUI`
|
||
|
||
It uses calculated roll data from the Direct Calculation tab and estimates loading capacity for transport presets or custom dimensions.
|
||
|
||
Preset transport units include:
|
||
|
||
- 20ft Container
|
||
- 40ft Container
|
||
- 40ft High Cube
|
||
- LKW Sattelzug
|
||
- LKW Tandem
|
||
|
||
The optimizer calculates limiting scenarios by:
|
||
|
||
- Weight
|
||
- Volume
|
||
- Geometry
|
||
|
||
It also renders a side-view SVG visualization of the loading arrangement.
|
||
|
||
### Standard Deviation Modules
|
||
|
||
There are standalone/static modules for standard deviation logic:
|
||
|
||
- `static/stddev_calculator.js`
|
||
- `static/rollcalc_stddev_ranges.js`
|
||
- `static/rollcalc_stddev_integration.js`
|
||
|
||
These provide or describe range calculations for material thickness, area weight, roll diameter, and roll weight. Check actual script inclusion before treating them as active in production, because the current template already contains inline stddev/tolerance behavior.
|
||
|
||
### Admin UI
|
||
|
||
RollCalc no longer contains an admin UI or admin API. Login/access logging remains in the backend, but logs are not exposed through a RollCalc admin screen.
|
||
|
||
Administration and maintenance of `article-data.json` is planned for a separate application. RollCalc should continue to consume `static/article-data.json` read-only.
|
||
|
||
## Static Assets and Data Files
|
||
|
||
### `static/article-data.json`
|
||
|
||
Primary product/article dataset used by the active calculator UI.
|
||
|
||
### `static/config.json`
|
||
|
||
JSON configuration for forklift/heavy-roll rules. The active template also contains an inline `window.APP_CONFIG`, so developers should verify which config source is authoritative before changing rule behavior.
|
||
|
||
### `access_log.json`
|
||
|
||
JSON audit log written by `app.py`.
|
||
|
||
Important implementation detail: each logged access reads and rewrites the entire JSON file. This is simple but not concurrency-safe and can become inefficient as the file grows.
|
||
|
||
### `build_info.json`
|
||
|
||
Deployment/build metadata displayed in the site footer.
|
||
|
||
Expected fields:
|
||
|
||
- `version`
|
||
- `branch`
|
||
- `commit`
|
||
- `timestamp`
|
||
|
||
`app.py` loads this file centrally at startup and exposes it to all templates as `build_info`. If the file is missing, invalid, or a field is empty, the affected values fall back to `unknown` and the website continues to work.
|
||
|
||
### `fix_article_data.py`
|
||
|
||
Utility script that updates relative frontend fetch/register paths to Flask-style `/static/...` paths and checks that key static files exist.
|
||
|
||
## Development Notes
|
||
|
||
- The codebase is currently closer to a single-page static calculator wrapped by Flask than to a conventional Flask MVC app.
|
||
- The active calculator logic is concentrated in `templates/roll_calculator.html`.
|
||
- There are duplicated or legacy-looking files with similar names. Before editing JavaScript under `static/`, confirm it is actually referenced by the active template.
|
||
- The documentation under `docs/` contains deployment and feature notes, but some filenames and route assumptions may not match the current app exactly.
|
||
- The Flask dev server is used for local development only. Production should use a WSGI server.
|
||
- Use `scripts/manage_users.py` to add users, rotate passwords, or delete users.
|
||
|
||
## Known Risks and Maintenance Items
|
||
|
||
- Password hashes are currently stored in `config/users.json`; a secrets manager or protected deployment-specific config would be more robust for production.
|
||
- `access_log.json` is not safe for concurrent writes.
|
||
- `access_log.json` grows without rotation or retention limits.
|
||
- The custom `/static/<path:filename>` route is intended to protect static files, but Flask also creates a default static route unless disabled. Verify effective route behavior before relying on static-file protection.
|
||
- RollCalc no longer includes an admin UI/API; article data administration belongs in a separate application.
|
||
- There is no visible automated test suite.
|
||
- The main template is large and mixes layout, styling, data loading, calculations, and UI behavior.
|
||
- The disclaimer confirmation is client-side only and is not persisted or audited server-side.
|