# PROJECT_KNOWLEDGE.md Project-specific technical and domain knowledge for RollCalcPython. ## Purpose RollCalcPython is an internal roll calculator for Naue roll products. The backend is a minimal Flask application that provides authentication, routing, static file delivery, and access logs. Most domain behavior runs in the browser inside `templates/roll_calculator.html`. The tool is not intended as an unchecked source of truth. Inputs and outputs must be checked for plausibility before operational use. ## Current Architecture Backend: - `app.py` creates the Flask app. - HTTP Basic Auth is implemented with `Flask-HTTPAuth`. - Users are configured in local deployment file `config/users.json` with Werkzeug password hashes. This file is ignored by Git. - `/` renders the active calculator template. - `/help` renders the authenticated Help landing page. - `/help/user-manual` renders `docs/de/user_manual.md` server-side inside the RollCalc Help layout. - `/help/quick-reference` renders `docs/en/quick_reference.md` server-side inside the RollCalc Help layout. - `/help/recent-changes` renders `docs/de/recent_changes.md` server-side inside the RollCalc Help layout. - `/help/user-manual/screenshots/` serves German manual screenshots from `docs/de/screenshots/`. - `/static/` is intended to serve static files behind Basic Auth. - `/api/health` returns health/version information. - `/api/user` returns the authenticated user. - Access events are appended to `access_log.json`. - `build_info.json` is loaded at startup and exposed to all templates as `build_info`. Frontend: - `templates/roll_calculator.html` is the active application page. - The page contains most CSS and JavaScript inline. - `window.ARTICLE_DATA` is loaded from `/static/article-data.json`. - `window.APP_CONFIG` is currently defined inline for forklift rules. - A disclaimer modal blocks use until the user checks the confirmation checkbox. - The footer displays build metadata: version, branch, commit, and timestamp. ## Build Info Build/deployment metadata is read from: ```text build_info.json ``` Expected fields: - `version` - `branch` - `commit` - `timestamp` If `build_info.json` is missing, malformed, or does not contain a usable value, RollCalc falls back to `unknown` for that value and continues serving the site. The data is loaded centrally in `app.py` and made available to every template as `build_info`. ## Cache and Release Visibility RollCalc uses the current build identifier to cache-bust RollCalc-owned static assets referenced by active templates. The preferred identifier is `build_info.commit`; if it is missing or `unknown`, the fallback is `build_info.version`. Dynamic HTML responses are sent with `Cache-Control: no-cache` so the calculator and Help pages are revalidated after deployments. Static assets are not globally marked no-cache; versioned URLs are used for active static JSON assets instead. For releases, keep these sources aligned: - `build_info.json` - the default `VERSION` in `scripts/update_build_info.sh`, unless deployment overrides it - the newest heading in `docs/de/recent_changes.md` - `version` in `static/recent_changes.json` The Recent Changes page includes a persistent force-reload fallback note for users whose browser still shows an older interface after deployment. ## Help and User Manual The in-app Help area keeps `docs/de/user_manual.md` as the leading German documentation source. RollCalc reads the Markdown file on each `/help/user-manual` request and renders it server-side with `markdown-it-py`. `docs/en/quick_reference.md` is the English Quick Reference source and is rendered at `/help/quick-reference`. It is derived from the full German User Manual and must remain a concise workflow reference rather than an independently diverging technical source. The documentation structure is prepared for language-specific manuals: ```text docs/ de/ user_manual.md screenshots/ en/ quick_reference.md ``` Additional languages can follow the same structure later. The current public route still opens the German manual, the Quick Reference is currently English only, and no language switcher is implemented. Rendering rules: - Raw HTML from the Markdown source is disabled. - Heading ids and the table of contents are generated from the Markdown content. - Relative image references such as `screenshots/disclaimer.png` are rewritten to the authenticated manual screenshot route. - Screenshots belong in the active language's `screenshots/` directory, currently `docs/de/screenshots/`; the screenshot route must remain limited to that directory. The Help pages use the same HTTP Basic Auth protection as the calculator. ### Recent Changes and What's New Full user-facing release notes are maintained in: ```text docs/de/recent_changes.md ``` The calculator header links directly to `/help/user-manual`. The Help landing page lists only existing documents, currently User Manual, Quick Reference, and Recent Changes. The startup What's New dialog uses `build_info.version` and is suppressed when the version is empty or `unknown`. The last acknowledged version is stored only in browser `localStorage` under: ```text rollcalc_last_seen_version ``` The short dialog item list is maintained separately in: ```text static/recent_changes.json ``` This JSON is a compact summary for the dialog, not the complete release history. It contains a `version` field and an `items` list. The browser displays the dialog only when the JSON version matches `build_info.version`; mismatched or invalid JSON must not block the calculator. ## Authentication RollCalc uses HTTP Basic Auth. User entries are stored in the local deployment file: ```text config/users.json ``` This file is intentionally ignored by Git. The versioned file `config/users.example.json` documents the JSON format only and must not contain real usernames, hashes, or passwords. The file stores username-to-password-hash mappings: ```json { "username": "" } ``` Password verification uses `werkzeug.security.check_password_hash`. Users are managed with: ```bash python3 scripts/manage_users.py ``` The management tool provides a text menu for listing users, creating users, changing passwords, and deleting users. New hashes use the existing RollCalc method `pbkdf2:sha256:600000`. The Flask app requires a readable, valid, non-empty `config/users.json` at startup and does not silently create an empty user file. If the file is missing or invalid, startup should fail with a message pointing to `python3 scripts/manage_users.py`. Passwords must not be logged. Password hashes should only be stored in `config/users.json` or a future protected deployment-specific secret source. Deployment notes: - The systemd/service user must be able to read `config/users.json`. - Suitable server permissions can be owner `martin`, group `www-data`, mode `640`, adjusted to the actual deployment users. - Do not hard-code deployment owners or groups in Python. - Back up the productive `config/users.json` before deploying or replacing a server instance. ## Roll Geometry Calculations assume an ideal cylindrical winding. Assumptions: - Constant material thickness. - No compression. - No air gaps. - Roll geometry is derived mathematically, not physically measured in the app. Nominal diameter formula used by the Direct Calculation tab: ```text D = sqrt(d^2 + (4 * L * 1000 * t) / pi) ``` Variables: - `D`: roll diameter in mm. - `d`: core diameter in mm. - `L`: product length in m. - `t`: material thickness in mm. When a tolerance/stddev value is present, the UI also displays a `-2σ` and `+2σ` diameter range. ## Product Length and Extrapolation Product length from a known diameter is calculated by rearranging the diameter formula: ```text L = (pi / (4 * t)) * (D^2 - d^2) / 1000 ``` The extrapolation tab estimates a new diameter from a known roll diameter/length pair: ```text D1 = sqrt(d^2 + (L1 / L0) * (D0^2 - d^2)) ``` Variables: - `D0`: known/measured roll diameter. - `L0`: known/measured roll length. - `L1`: target length. - `D1`: extrapolated roll diameter. ## Roll Weight Roll weight is calculated client-side when width, area weight, and length are available: ```text weight_kg = area_weight_g_m2 * length_m * width_m / 1000 ``` Material thickness and area weight values are loaded from article data and are generated automatically. They are not guaranteed to be complete or reviewed. ## Article Data Active data source: ```text static/article-data.json ``` The UI expects article records with fields such as: - `nr` - `name` - `thickness` - `thickness_stddev` - `area_weight` - `area_weight_stddev` - `core_type` Observed additional fields include min/max/count values for material thickness and area weight. Important data rule: - Article data is generated from ERP-derived sources. - These values should not be manually changed unless the task is explicitly data maintenance. Article-data architecture decision: - Article data should evolve from a simple article catalogue into a shared production knowledge base. - Each article may optionally provide production-related default values. - Initial defaults include `Product Thickness`, `Area Weight`, `Core Diameter`, and `Roll Width`. - Future production-related defaults can be added without changing the overall architecture. - When an article is selected, available defaults are copied into the calculator fields. - Missing optional values must never overwrite existing user input. - All automatically populated values remain editable by the user. - The planned Article-Data-Admin application will become the authoritative editor for these production defaults. Known domain caveat from existing project notes: - For articles in the groups Secugrid, Combigrid, Carbofol MF/MF, Carbofol F/F, Carbofol s/F, and Carbofol BF/s, the thickness from `article-data.json` must not be used without domain validation. ## Forklift and Heavy-Roll Rules The active template currently evaluates forklift warnings through `checkForklift()` and inline `window.APP_CONFIG`. Current inline rule behavior: - Applies to category `bentofix`. - Warning threshold: `1700 kg`. - Hard limit: `2750 kg`. - Minimum core outer diameter: `170 mm`. There is also a richer JSON configuration in: ```text static/config.json ``` That file includes localized messages and additional equipment requirements. Before changing forklift behavior, verify whether the active inline config or the static JSON should be authoritative. ## Load Optimizer The Load Optimizer is implemented inline in `templates/roll_calculator.html`. Classes: - `LoadOptimizer` - `LoadOptimizerUI` It uses calculated roll data from the Direct Calculation tab: - Roll diameter. - Core diameter. - Roll width. - Roll weight. - Product length. - Square meters per roll. It supports transport presets: - 20ft Container. - 40ft Container. - 40ft High Cube. - LKW Sattelzug. - LKW Tandem. It calculates limiting scenarios by: - Weight. - Volume. - Geometry. It also draws a side-view SVG visualization. ## Disclaimer Gate The active calculator page includes a disclaimer modal shown after Basic Auth login and before calculator use. The modal: - Contains German and English disclaimer text. - Requires checkbox confirmation. - Enables the confirmation button only after the checkbox is selected. - Hides the overlay after confirmation. This is client-side only. It is not persisted, logged, or enforced server-side. ## Admin Area State RollCalc no longer contains an admin UI or admin API. The previous `/admin/logs` route and `templates/admin.html` have been removed. Login/access logging remains part of RollCalc, but log viewing and article-data administration should not be implemented inside this app. Maintenance of `article-data.json` is planned for a separate application. ## Known Technical Risks - Password hashes are currently configured in `app.py`; this should eventually move to a protected external configuration or secrets mechanism. - Basic Auth only; no sessions or role framework beyond the user dictionary. - `access_log.json` is rewritten on every logged request and is not concurrency-safe. - No log rotation or retention policy is implemented. - Flask's default static route may conflict with the intended authenticated `/static/` behavior; verify effective routing before relying on protected static files. - Most active logic is concentrated in one large HTML template. - Multiple similar static JavaScript files exist; not all are necessarily active. - No automated test suite is visible. - Some docs and filenames in `docs/` may reflect earlier package/archive versions.