Five plan-creation number inputs accept out-of-range values until Save is clicked, at which point a backend error message appears. UX is inconsistent with other range fields (e.g. Admin > Purchasing Policies > Grace Period) that validate inline.
- 3.11
#plan-coverage (frontend/src/index.html:799) — min=0 max=100, no live validation.
- 3.16
#ramp-step-percent (index.html:829) — min=1 max=100, no live validation.
- 3.17
#ramp-interval-days (index.html:830) — min=1 and NO max at all; up-arrow runs unbounded past 365.
- 3.19 same input accepts scientific notation (
1e+30); on save parseInt yields Infinity/NaN producing weird error messages.
- 3.24
#plan-notify-days (index.html:855) — min=1 max=30, no live validation.
Fix direction
(a) Add max="365" to ramp-interval-days and cap the same input to digits-only (regex ^\d+$).
(b) Wire input event handlers in frontend/src/plans.ts that clamp parseInt(target.value) to [min, max], reject non-integer/scientific via regex, and toggle an inline error span. One helper covers all five inputs.
(c) Mirror in the backend (internal/config/validation.go) where not already present.
Surfaced by QA spreadsheet rows 3.11 / 3.16 / 3.17 / 3.19 / 3.24.
Five plan-creation number inputs accept out-of-range values until Save is clicked, at which point a backend error message appears. UX is inconsistent with other range fields (e.g. Admin > Purchasing Policies > Grace Period) that validate inline.
#plan-coverage(frontend/src/index.html:799) —min=0 max=100, no live validation.#ramp-step-percent(index.html:829) —min=1 max=100, no live validation.#ramp-interval-days(index.html:830) —min=1and NO max at all; up-arrow runs unbounded past 365.1e+30); on saveparseIntyields Infinity/NaN producing weird error messages.#plan-notify-days(index.html:855) —min=1 max=30, no live validation.Fix direction
(a) Add
max="365"toramp-interval-daysand cap the same input to digits-only (regex^\d+$).(b) Wire
inputevent handlers infrontend/src/plans.tsthat clampparseInt(target.value)to[min, max], reject non-integer/scientific via regex, and toggle an inline error span. One helper covers all five inputs.(c) Mirror in the backend (
internal/config/validation.go) where not already present.Surfaced by QA spreadsheet rows 3.11 / 3.16 / 3.17 / 3.19 / 3.24.