[Feature] Streamline Trip Logging: Two-Stage Draft & Confirmation Workflow, Single-Draft Integrity, and Inline Validation Feedback #2

Closed
opened 2026-09-04 14:43:31 +02:00 by JackPrince · 0 comments
Owner

1. Background & Problem Statement

User feedback indicates that input errors are difficult to diagnose and resolve due to ambiguous error handling. Code inspection revealed several architectural and UX bottlenecks:

  1. Premature Confirmation by Default: New trips default to status: 'confirmed'. Checking the confirmed box automatically injects a fictitious end time (now + 1 hour), which violates GoBD principles.
  2. Drafts Blocked in the UI: While the API supports minimal drafts (vehicle_id, started_at, odometer_start), an HTML5 required attribute on odometer_end prevents saving drafts in the frontend.
  3. Opaque Validation Errors: On HTTP 422 responses, the client displays a generic error message (The given data was invalid.) and discards field-level error messages (payload.errors).
  4. Lack of Single-Draft Constraints: Vehicles can accumulate multiple unconfirmed drafts, and selecting a vehicle does not auto-resume an existing open draft.

2. Proposed Architecture & Workflow

A. Two-Stage Trip Lifecycle

  • Stage 1: Save Draft (Fahrt beginnen / Entwurf speichern)
    • Requires only: vehicle_id, started_at, and odometer_start.
    • Destination, purpose, end time, and end odometer remain optional.
  • Stage 2: Check & Confirm (Fahrt prüfen & bestätigen)
    • Becomes available once all mandatory GoBD fields are filled and valid.
    • Locks the trip into status: 'confirmed', requiring an audit change reason for subsequent edits.

B. Single-Draft Integrity & Auto-Resume

  • Backend: Enforce a validation rule rejecting new drafts if an unconfirmed draft already exists for the vehicle.
  • Frontend: Selecting a vehicle with an active draft automatically loads that draft into the form, displays a prominent banner ("Resuming open draft from [Date]"), and provides a "Discard Draft" button.

C. Inline Feedback & Pre-Flight Checks

  • Deliver server-side HTTP 422 field errors directly to their corresponding form inputs.
  • Introduce a pre-flight checklist above the submit button verifying odometer continuity against the preceding trip, absence of time overlaps, and completion status.

D. Transparent Geolocation State

  • Clearly indicate address/GPS state in LocationPicker ("GPS captured", "Selected from bookmarks", "Manually edited — coordinates cleared").

3. Acceptance Criteria

  • Trips default to status: 'draft'. Fictitious +1h end-time calculation is removed.
  • HTML5 required attributes do not prevent submitting minimal drafts.
  • Primary action buttons clearly separate "Save Draft" from "Confirm Trip".
  • Form displays a live progress counter (e.g. Draft · 3 fields missing for confirmation).
  • Backend blocks duplicate drafts per vehicle with a descriptive HTTP 422 error.
  • Selecting a vehicle with an existing draft auto-populates the form and exposes a "Discard Draft" option.
  • Field-level API validation errors render directly beside the affected inputs.
  • Pre-flight checks visually validate odometer continuity and time overlap before submission.
  • Geolocation status reflects whether coordinates originate from GPS, saved bookmarks, or manual entry.

4. Affected Code References

  • client/src/features/trips/tripFormModel.ts
  • client/src/features/trips/TripFormCard.tsx
  • client/src/features/trips/TripsPage.tsx
  • client/src/components/LocationPicker.tsx
  • client/src/lib/api.ts
  • app/Services/TripIntegrityService.php
  • app/Http/Requests/StoreTripRequest.php
  • routes/console.php
## 1. Background & Problem Statement User feedback indicates that input errors are difficult to diagnose and resolve due to ambiguous error handling. Code inspection revealed several architectural and UX bottlenecks: 1. **Premature Confirmation by Default:** New trips default to `status: 'confirmed'`. Checking the confirmed box automatically injects a fictitious end time (`now + 1 hour`), which violates GoBD principles. 2. **Drafts Blocked in the UI:** While the API supports minimal drafts (`vehicle_id`, `started_at`, `odometer_start`), an HTML5 `required` attribute on `odometer_end` prevents saving drafts in the frontend. 3. **Opaque Validation Errors:** On HTTP 422 responses, the client displays a generic error message (`The given data was invalid.`) and discards field-level error messages (`payload.errors`). 4. **Lack of Single-Draft Constraints:** Vehicles can accumulate multiple unconfirmed drafts, and selecting a vehicle does not auto-resume an existing open draft. --- ## 2. Proposed Architecture & Workflow ### A. Two-Stage Trip Lifecycle * **Stage 1: Save Draft (Fahrt beginnen / Entwurf speichern)** * Requires only: `vehicle_id`, `started_at`, and `odometer_start`. * Destination, purpose, end time, and end odometer remain optional. * **Stage 2: Check & Confirm (Fahrt prüfen & bestätigen)** * Becomes available once all mandatory GoBD fields are filled and valid. * Locks the trip into `status: 'confirmed'`, requiring an audit change reason for subsequent edits. ### B. Single-Draft Integrity & Auto-Resume * **Backend:** Enforce a validation rule rejecting new drafts if an unconfirmed draft already exists for the vehicle. * **Frontend:** Selecting a vehicle with an active draft automatically loads that draft into the form, displays a prominent banner (*"Resuming open draft from [Date]"*), and provides a *"Discard Draft"* button. ### C. Inline Feedback & Pre-Flight Checks * Deliver server-side HTTP 422 field errors directly to their corresponding form inputs. * Introduce a pre-flight checklist above the submit button verifying odometer continuity against the preceding trip, absence of time overlaps, and completion status. ### D. Transparent Geolocation State * Clearly indicate address/GPS state in `LocationPicker` (*"GPS captured"*, *"Selected from bookmarks"*, *"Manually edited — coordinates cleared"*). --- ## 3. Acceptance Criteria - [ ] Trips default to `status: 'draft'`. Fictitious `+1h` end-time calculation is removed. - [ ] HTML5 `required` attributes do not prevent submitting minimal drafts. - [ ] Primary action buttons clearly separate *"Save Draft"* from *"Confirm Trip"*. - [ ] Form displays a live progress counter (e.g. `Draft · 3 fields missing for confirmation`). - [ ] Backend blocks duplicate drafts per vehicle with a descriptive HTTP 422 error. - [ ] Selecting a vehicle with an existing draft auto-populates the form and exposes a *"Discard Draft"* option. - [ ] Field-level API validation errors render directly beside the affected inputs. - [ ] Pre-flight checks visually validate odometer continuity and time overlap before submission. - [ ] Geolocation status reflects whether coordinates originate from GPS, saved bookmarks, or manual entry. --- ## 4. Affected Code References * `client/src/features/trips/tripFormModel.ts` * `client/src/features/trips/TripFormCard.tsx` * `client/src/features/trips/TripsPage.tsx` * `client/src/components/LocationPicker.tsx` * `client/src/lib/api.ts` * `app/Services/TripIntegrityService.php` * `app/Http/Requests/StoreTripRequest.php` * `routes/console.php`
Sign in to join this conversation.
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
JackPrince/GoBDLogBook#2
No description provided.