Skip to content

Commit e7e9898

Browse files
aligneddevaligneddev
andauthored
008 quick ride entry (#26)
* feat: add quick ride entry options flow * fix: restore api test host startup and quick-options compile * 008 --------- Co-authored-by: aligneddev <aligneddev@github.com>
1 parent 54b317a commit e7e9898

22 files changed

Lines changed: 1448 additions & 4 deletions

File tree

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
# Specification Quality Checklist: Quick Ride Entry from Past Rides
2+
3+
**Purpose**: Validate specification completeness and quality before proceeding to planning
4+
**Created**: 2026-03-30
5+
**Feature**: [spec.md](../spec.md)
6+
7+
## Content Quality
8+
9+
- [x] No implementation details (languages, frameworks, APIs)
10+
- [x] Focused on user value and business needs
11+
- [x] Written for non-technical stakeholders
12+
- [x] All mandatory sections completed
13+
14+
## Requirement Completeness
15+
16+
- [x] No [NEEDS CLARIFICATION] markers remain
17+
- [x] Requirements are testable and unambiguous
18+
- [x] Success criteria are measurable
19+
- [x] Success criteria are technology-agnostic (no implementation details)
20+
- [x] All acceptance scenarios are defined
21+
- [x] Edge cases are identified
22+
- [x] Scope is clearly bounded
23+
- [x] Dependencies and assumptions identified
24+
25+
## Feature Readiness
26+
27+
- [x] All functional requirements have clear acceptance criteria
28+
- [x] User scenarios cover primary flows
29+
- [x] Feature meets measurable outcomes defined in Success Criteria
30+
- [x] No implementation details leak into specification
31+
32+
## Notes
33+
34+
- Validation pass completed on 2026-03-30; no blocking issues found.
35+
- Spec is ready for `/speckit.plan`.
Lines changed: 81 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,81 @@
1+
openapi: 3.0.3
2+
info:
3+
title: BikeTracking Quick Ride Options API
4+
version: 1.0.0
5+
description: Authenticated quick-entry options for record-ride prefill.
6+
7+
paths:
8+
/api/rides/quick-options:
9+
get:
10+
summary: Get up to 5 distinct quick ride options for the authenticated rider
11+
operationId: getQuickRideOptions
12+
responses:
13+
'200':
14+
description: Quick options resolved.
15+
content:
16+
application/json:
17+
schema:
18+
$ref: '#/components/schemas/QuickRideOptionsResponse'
19+
'401':
20+
description: Unauthorized
21+
content:
22+
application/json:
23+
schema:
24+
$ref: '#/components/schemas/ErrorResponse'
25+
'500':
26+
description: Unexpected retrieval failure
27+
content:
28+
application/json:
29+
schema:
30+
$ref: '#/components/schemas/ErrorResponse'
31+
32+
components:
33+
schemas:
34+
QuickRideOption:
35+
type: object
36+
required:
37+
- miles
38+
- rideMinutes
39+
- lastUsedAtLocal
40+
properties:
41+
miles:
42+
type: number
43+
exclusiveMinimum: 0
44+
maximum: 200
45+
rideMinutes:
46+
type: integer
47+
minimum: 1
48+
lastUsedAtLocal:
49+
type: string
50+
format: date-time
51+
description: Most recent local ride date/time for this miles-duration pair.
52+
53+
QuickRideOptionsResponse:
54+
type: object
55+
required:
56+
- options
57+
- generatedAtUtc
58+
properties:
59+
options:
60+
type: array
61+
maxItems: 5
62+
items:
63+
$ref: '#/components/schemas/QuickRideOption'
64+
generatedAtUtc:
65+
type: string
66+
format: date-time
67+
68+
ErrorResponse:
69+
type: object
70+
required:
71+
- code
72+
- message
73+
properties:
74+
code:
75+
type: string
76+
message:
77+
type: string
78+
details:
79+
type: array
80+
items:
81+
type: string
Lines changed: 94 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,94 @@
1+
# Data Model: Quick Ride Entry from Past Rides
2+
3+
**Feature**: Quick Ride Entry from Past Rides (001)
4+
**Branch**: `008-quick-ride-entry`
5+
**Date**: 2026-03-30
6+
**Phase**: Phase 1 - Design & Contracts
7+
8+
## Overview
9+
10+
This feature introduces a read-side model for reusable quick options derived from historical ride records. No new write-side event type is required; quick options are computed from existing rider ride data and consumed by the record-ride UI.
11+
12+
## Entities
13+
14+
### QuickRideOption
15+
16+
Represents one distinct reusable pair of values shown to the rider for fast prefill.
17+
18+
| Field | Type | Required | Validation | Notes |
19+
|-------|------|----------|------------|-------|
20+
| miles | number | Yes | > 0 and <= 200 | Copied into ride form miles field |
21+
| rideMinutes | integer | Yes | > 0 | Copied into ride form duration field |
22+
| lastUsedAtLocal | string (date-time) | Yes | valid date-time | Most recent occurrence timestamp used for ordering |
23+
24+
### QuickRideOptionsResponse
25+
26+
API response for quick option retrieval.
27+
28+
| Field | Type | Required | Description |
29+
|-------|------|----------|-------------|
30+
| options | array of QuickRideOption | Yes | Up to 5 rider-scoped distinct options |
31+
| generatedAtUtc | string (date-time) | Yes | Server timestamp for response generation |
32+
33+
### RideEntryFormState (Frontend)
34+
35+
Client form state that receives copied values.
36+
37+
| Field | Type | Required | Description |
38+
|-------|------|----------|-------------|
39+
| miles | number or empty | Yes | User-editable required field |
40+
| rideMinutes | integer or empty | Yes | User-editable required field for this feature's quick-copy behavior |
41+
| isDirty | boolean | Yes | Indicates local edits after prefill/manual changes |
42+
| selectedQuickOption | QuickRideOption or null | No | Tracks current source option for UX feedback |
43+
44+
## Relationships
45+
46+
- One rider can have many Ride Entries.
47+
- Many historical Ride Entries map to one QuickRideOption when `(miles, rideMinutes)` values are identical.
48+
- QuickRideOptionsResponse is derived from the rider's ride history and is not persisted as a standalone table requirement for this phase.
49+
50+
## Derivation Rules
51+
52+
1. Filter ride records to current authenticated rider.
53+
2. Exclude records missing miles or rideMinutes.
54+
3. Group by `(miles, rideMinutes)`.
55+
4. For each group, keep most recent `rideDateTimeLocal` as `lastUsedAtLocal`.
56+
5. Sort groups by `lastUsedAtLocal` descending.
57+
6. Return top 5.
58+
59+
## State Transitions
60+
61+
1. Rider opens record-ride page.
62+
2. Frontend requests `GET /api/rides/quick-options`.
63+
3. Backend returns up to five distinct options.
64+
4. Rider selects one option.
65+
5. Frontend copies option values into `miles` and `rideMinutes` fields.
66+
6. Rider may edit values.
67+
7. Rider submits existing save flow; normal validation applies.
68+
8. On save success, frontend refreshes quick options for future entries.
69+
70+
## Validation Rules
71+
72+
### API Query Layer
73+
74+
- Require authenticated rider context.
75+
- Ensure response contains at most 5 options.
76+
- Ensure each option is unique by exact `(miles, rideMinutes)` pair.
77+
- Ensure each returned option contains valid positive values.
78+
79+
### Frontend Layer
80+
81+
- Option selection must not trigger API write/save.
82+
- Copied values remain editable.
83+
- Existing validation messages and submission guards remain unchanged.
84+
85+
### Security/Isolation
86+
87+
- Query must return only options derived from the authenticated rider's rides.
88+
- Cross-user data leakage is prohibited.
89+
90+
## Failure and Empty-State Behavior
91+
92+
- If options query returns empty array, quick-entry section renders empty/hidden state and manual entry remains available.
93+
- If query fails, show non-blocking error and keep manual ride entry usable.
94+
- If rider has fewer than 5 valid distinct patterns, return only available options.

specs/008-quick-ride-entry/plan.md

Lines changed: 90 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,90 @@
1+
# Implementation Plan: Quick Ride Entry from Past Rides
2+
3+
**Branch**: `008-quick-ride-entry` | **Date**: 2026-03-30 | **Spec**: `/specs/008-quick-ride-entry/spec.md`
4+
**Input**: Feature specification from `/specs/008-quick-ride-entry/spec.md`
5+
6+
**Note**: This template is filled in by the `/speckit.plan` command. See `.specify/templates/plan-template.md` for the execution workflow.
7+
8+
## Summary
9+
10+
Add a quick-entry assist to the existing record-ride flow so authenticated riders can select from up to five distinct prior miles-duration combinations and prefill form fields without auto-saving. The feature introduces a rider-scoped query contract for quick options, keeps manual editing and validation unchanged, and updates options after successful new ride submission.
11+
12+
## Technical Context
13+
14+
**Language/Version**: C# (.NET 10), TypeScript (React 19 + Vite), F# domain project available
15+
**Primary Dependencies**: ASP.NET Core Minimal API, EF Core (SQLite provider), existing rides endpoints and auth/session flow, React form state patterns
16+
**Storage**: SQLite local-file profile via EF Core; quick options derived from existing rider ride data (no new storage engine)
17+
**Testing**: `dotnet test BikeTracking.slnx`, frontend `npm run lint`, `npm run build`, `npm run test:unit`, and `npm run test:e2e` for cross-layer flow
18+
**Target Platform**: Local-first Aspire web app in DevContainer (browser frontend + .NET API)
19+
**Project Type**: Web application (React frontend + Minimal API backend)
20+
**Performance Goals**: Quick-options query should stay under constitutional API target (<500ms p95); quick option selection should prefill form immediately on client interaction
21+
**Constraints**: Rider-scoped data isolation, no auto-save on option select, max 5 distinct options, preserve existing validation semantics, offline/error fallback to manual entry
22+
**Scale/Scope**: One query endpoint for quick options, ride-entry UI enhancement, and tests covering duplicate suppression, limit behavior, and edit-after-prefill
23+
24+
## Constitution Check
25+
26+
*GATE: Must pass before Phase 0 research. Re-check after Phase 1 design.*
27+
28+
### Pre-Research Gate Review
29+
30+
| Gate | Status | Notes |
31+
|------|--------|-------|
32+
| DevContainer-only development | PASS | Planning commands and artifact generation executed inside the workspace container. |
33+
| Clean architecture boundaries | PASS | Feature boundaries remain in ride-entry UI + API query service over existing ride data. |
34+
| React + TypeScript consistency | PASS | Quick options rendered and applied through typed React state/form patterns. |
35+
| Data validation depth | PASS | Existing client/API/DB validation retained; quick options only prefill values, not bypass rules. |
36+
| Contract-first collaboration | PASS | Dedicated quick-options API contract defined before implementation. |
37+
| TDD gated workflow | PASS WITH ACTION | Tasks must enforce red-first tests and explicit user confirmation of failing tests prior to coding. |
38+
| Performance and observability expectations | PASS | Query limited to 5 distinct values and rider-scoped filter; metrics/logging remain on current pipeline. |
39+
40+
No constitutional violations identified.
41+
42+
### Post-Design Gate Re-Check
43+
44+
| Gate | Status | Notes |
45+
|------|--------|-------|
46+
| Architecture and modularity | PASS | Design isolates quick-option derivation in query path and keeps create-ride command flow unchanged. |
47+
| Contract compatibility | PASS | New endpoint is additive and does not alter existing ride history or record-ride contract behavior. |
48+
| Validation and safety | PASS | Prefill can be edited and still must pass existing required-field/constraint validation. |
49+
| UX consistency and accessibility | PASS | Feature remains optional, non-blocking, and compatible with existing entry form behavior. |
50+
| Verification matrix coverage | PASS WITH ACTION | Quickstart includes required backend/frontend/e2e validation commands for cross-layer changes. |
51+
52+
## Project Structure
53+
54+
### Documentation (this feature)
55+
56+
```text
57+
specs/008-quick-ride-entry/
58+
├── plan.md
59+
├── research.md
60+
├── data-model.md
61+
├── quickstart.md
62+
├── contracts/
63+
│ └── quick-ride-options-api.yaml
64+
└── tasks.md # generated by /speckit.tasks
65+
```
66+
67+
### Source Code (repository root)
68+
```text
69+
src/
70+
├── BikeTracking.Api/
71+
│ ├── Endpoints/
72+
│ ├── Application/
73+
│ ├── Contracts/
74+
│ └── Infrastructure/
75+
├── BikeTracking.Api.Tests/
76+
│ ├── Endpoints/
77+
│ ├── Application/
78+
│ └── Infrastructure/
79+
└── BikeTracking.Frontend/
80+
├── src/
81+
│ ├── pages/
82+
│ ├── components/
83+
│ └── services/
84+
└── tests/
85+
```
86+
87+
**Structure Decision**: Reuse the existing web-app split and implement a query-side quick-option slice: backend exposes rider-scoped quick options from existing rides data, frontend consumes options on record-ride load and applies selection to current form state.
88+
89+
## Complexity Tracking
90+
No constitutional violations requiring justification.

0 commit comments

Comments
 (0)