fix(projects): server-side validation for name + budget (fix Budget Hours 422) [PMS-324] #243

Merged
vas2000-work merged 2 commits from fix/PMS-324-project-input-validation into main 2026-06-15 18:55:18 +02:00
Owner

What

Project create/edit accepted invalid input on the server side (PMS-324).

  • The mokosh-apps client posts budgets as JSON numbers, but budget_hours / budget_amount (Option<Decimal>) only deserialized from strings, so a numeric budget was rejected by Axum's Json extractor as a 422 before validation ran. This is the reported "Budget Hours request failed" (HTTP 422), while budget_amount: 500 happened to be entered/sent in a form that also tripped it.
  • name had only a 255-char cap; budgets had no range/scale validation, so non-numeric ("Bobby Tables"), negative, oversized, and more-than-2-decimal values were silently accepted or overflowed the DECIMAL column (a 500 class).

Changes

  • Tolerant deserialization for both budget fields: accept a JSON number, a numeric string, or null. A number is parsed from its exact textual form (not via f64) so no floating-point drift is introduced.
  • name capped at 80 characters on create and update (per the PMS-324 decision).
  • New validate_budget_amount / validate_budget_hours: reject negatives, more than 2 decimal places, and magnitudes beyond the backing DECIMAL(12,2) / DECIMAL(10,2) columns. Invalid input returns a field-level 422 via the existing AppError::Validation mapping.
  • Unit tests for the validators; integration test project_input_validation covering the numeric-budget path (regression guard for the 422) plus the name-length, negative, >2dp, and non-numeric rejections.

Verification

  • cargo test --lib validation (container): green.
  • cargo test -p mokosh-server --test projects project_input_validation against the compose Postgres: green.
  • cargo clippy --all-targets -- -D warnings and cargo fmt --all --check: green.

Client-side inline errors for the same form are in MAPPS-176 (linked).

#PMS-324

## What Project create/edit accepted invalid input on the server side (PMS-324). - The mokosh-apps client posts budgets as JSON **numbers**, but `budget_hours` / `budget_amount` (`Option<Decimal>`) only deserialized from **strings**, so a numeric budget was rejected by Axum's `Json` extractor as a 422 *before* validation ran. This is the reported "Budget Hours request failed" (HTTP 422), while `budget_amount: 500` happened to be entered/sent in a form that also tripped it. - `name` had only a 255-char cap; budgets had no range/scale validation, so non-numeric ("Bobby Tables"), negative, oversized, and more-than-2-decimal values were silently accepted or overflowed the `DECIMAL` column (a 500 class). ## Changes - Tolerant deserialization for both budget fields: accept a JSON number, a numeric string, or null. A number is parsed from its exact textual form (not via `f64`) so no floating-point drift is introduced. - `name` capped at 80 characters on create and update (per the PMS-324 decision). - New `validate_budget_amount` / `validate_budget_hours`: reject negatives, more than 2 decimal places, and magnitudes beyond the backing `DECIMAL(12,2)` / `DECIMAL(10,2)` columns. Invalid input returns a field-level 422 via the existing `AppError::Validation` mapping. - Unit tests for the validators; integration test `project_input_validation` covering the numeric-budget path (regression guard for the 422) plus the name-length, negative, >2dp, and non-numeric rejections. ## Verification - `cargo test --lib validation` (container): green. - `cargo test -p mokosh-server --test projects project_input_validation` against the compose Postgres: green. - `cargo clippy --all-targets -- -D warnings` and `cargo fmt --all --check`: green. Client-side inline errors for the same form are in MAPPS-176 (linked). #PMS-324
fix(projects): validate name length and budget fields, accept numeric budgets
All checks were successful
E2E / Playwright against staging (pull_request) Successful in 36s
Check / fmt + clippy + compile + unit/doc tests (pull_request) Successful in 1m3s
Integration / integration tests (pull_request) Successful in 2m58s
0953a741f6
Project create/edit accepted invalid input. The mokosh-apps client posts budgets as JSON numbers, but budget_hours/budget_amount (Option<Decimal>) only deserialized from strings, so a numeric budget was rejected by Axum's Json extractor as a 422 before validation ran (the reported "Budget Hours request failed"). Name had only a 255-char cap and budgets had no range/scale checks, so non-numeric ("Bobby Tables"), negative, oversized, and more-than-2-decimal values were silently accepted or overflowed the DECIMAL column.

Accept a JSON number, numeric string, or null for both budget fields, parsing a number from its exact textual form so no floating-point drift is introduced. Cap name at 80 characters on create and update. Add validate_budget_amount/validate_budget_hours rejecting negatives, more than 2 decimal places, and magnitudes beyond the DECIMAL(12,2)/DECIMAL(10,2) columns; invalid input now returns a field-level 422. Add validator unit tests and an integration test covering the numeric-budget path and each rejection.

#PMS-324

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Merge branch 'main' into fix/PMS-324-project-input-validation
All checks were successful
Create release / Create release from merged PR (pull_request) Has been skipped
E2E / Playwright against staging (pull_request) Successful in 48s
Check / fmt + clippy + compile + unit/doc tests (pull_request) Successful in 1m9s
Integration / integration tests (pull_request) Successful in 2m53s
457be7fc10
vas2000-work deleted branch fix/PMS-324-project-input-validation 2026-06-15 18:55:18 +02:00
Sign in to join this conversation.
No reviewers
No labels
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set

Reference
psa-systems/mokosh-server!243
No description provided.