Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
35 changes: 35 additions & 0 deletions specs/008-quick-ride-entry/checklists/requirements.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
# Specification Quality Checklist: Quick Ride Entry from Past Rides

**Purpose**: Validate specification completeness and quality before proceeding to planning
**Created**: 2026-03-30
**Feature**: [spec.md](../spec.md)

## Content Quality

- [x] No implementation details (languages, frameworks, APIs)
- [x] Focused on user value and business needs
- [x] Written for non-technical stakeholders
- [x] All mandatory sections completed

## Requirement Completeness

- [x] No [NEEDS CLARIFICATION] markers remain
- [x] Requirements are testable and unambiguous
- [x] Success criteria are measurable
- [x] Success criteria are technology-agnostic (no implementation details)
- [x] All acceptance scenarios are defined
- [x] Edge cases are identified
- [x] Scope is clearly bounded
- [x] Dependencies and assumptions identified

## Feature Readiness

- [x] All functional requirements have clear acceptance criteria
- [x] User scenarios cover primary flows
- [x] Feature meets measurable outcomes defined in Success Criteria
- [x] No implementation details leak into specification

## Notes

- Validation pass completed on 2026-03-30; no blocking issues found.
- Spec is ready for `/speckit.plan`.
Original file line number Diff line number Diff line change
@@ -0,0 +1,81 @@
openapi: 3.0.3
info:
title: BikeTracking Quick Ride Options API
version: 1.0.0
description: Authenticated quick-entry options for record-ride prefill.

paths:
/api/rides/quick-options:
get:
summary: Get up to 5 distinct quick ride options for the authenticated rider
operationId: getQuickRideOptions
responses:
'200':
description: Quick options resolved.
content:
application/json:
schema:
$ref: '#/components/schemas/QuickRideOptionsResponse'
'401':
description: Unauthorized
content:
application/json:
schema:
$ref: '#/components/schemas/ErrorResponse'
'500':
description: Unexpected retrieval failure
content:
application/json:
schema:
$ref: '#/components/schemas/ErrorResponse'

components:
schemas:
QuickRideOption:
type: object
required:
- miles
- rideMinutes
- lastUsedAtLocal
properties:
miles:
type: number
exclusiveMinimum: 0
maximum: 200
rideMinutes:
type: integer
minimum: 1
lastUsedAtLocal:
type: string
format: date-time
description: Most recent local ride date/time for this miles-duration pair.

QuickRideOptionsResponse:
type: object
required:
- options
- generatedAtUtc
properties:
options:
type: array
maxItems: 5
items:
$ref: '#/components/schemas/QuickRideOption'
generatedAtUtc:
type: string
format: date-time

ErrorResponse:
type: object
required:
- code
- message
properties:
code:
type: string
message:
type: string
details:
type: array
items:
type: string
94 changes: 94 additions & 0 deletions specs/008-quick-ride-entry/data-model.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,94 @@
# Data Model: Quick Ride Entry from Past Rides

**Feature**: Quick Ride Entry from Past Rides (001)
**Branch**: `008-quick-ride-entry`
**Date**: 2026-03-30
**Phase**: Phase 1 - Design & Contracts

## Overview

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.

## Entities

### QuickRideOption

Represents one distinct reusable pair of values shown to the rider for fast prefill.

| Field | Type | Required | Validation | Notes |
|-------|------|----------|------------|-------|
| miles | number | Yes | > 0 and <= 200 | Copied into ride form miles field |
| rideMinutes | integer | Yes | > 0 | Copied into ride form duration field |
| lastUsedAtLocal | string (date-time) | Yes | valid date-time | Most recent occurrence timestamp used for ordering |

### QuickRideOptionsResponse

API response for quick option retrieval.

| Field | Type | Required | Description |
|-------|------|----------|-------------|
| options | array of QuickRideOption | Yes | Up to 5 rider-scoped distinct options |
| generatedAtUtc | string (date-time) | Yes | Server timestamp for response generation |

### RideEntryFormState (Frontend)

Client form state that receives copied values.

| Field | Type | Required | Description |
|-------|------|----------|-------------|
| miles | number or empty | Yes | User-editable required field |
| rideMinutes | integer or empty | Yes | User-editable required field for this feature's quick-copy behavior |
| isDirty | boolean | Yes | Indicates local edits after prefill/manual changes |
| selectedQuickOption | QuickRideOption or null | No | Tracks current source option for UX feedback |

## Relationships

- One rider can have many Ride Entries.
- Many historical Ride Entries map to one QuickRideOption when `(miles, rideMinutes)` values are identical.
- QuickRideOptionsResponse is derived from the rider's ride history and is not persisted as a standalone table requirement for this phase.

## Derivation Rules

1. Filter ride records to current authenticated rider.
2. Exclude records missing miles or rideMinutes.
3. Group by `(miles, rideMinutes)`.
4. For each group, keep most recent `rideDateTimeLocal` as `lastUsedAtLocal`.
5. Sort groups by `lastUsedAtLocal` descending.
6. Return top 5.

## State Transitions

1. Rider opens record-ride page.
2. Frontend requests `GET /api/rides/quick-options`.
3. Backend returns up to five distinct options.
4. Rider selects one option.
5. Frontend copies option values into `miles` and `rideMinutes` fields.
6. Rider may edit values.
7. Rider submits existing save flow; normal validation applies.
8. On save success, frontend refreshes quick options for future entries.

## Validation Rules

### API Query Layer

- Require authenticated rider context.
- Ensure response contains at most 5 options.
- Ensure each option is unique by exact `(miles, rideMinutes)` pair.
- Ensure each returned option contains valid positive values.

### Frontend Layer

- Option selection must not trigger API write/save.
- Copied values remain editable.
- Existing validation messages and submission guards remain unchanged.

### Security/Isolation

- Query must return only options derived from the authenticated rider's rides.
- Cross-user data leakage is prohibited.

## Failure and Empty-State Behavior

- If options query returns empty array, quick-entry section renders empty/hidden state and manual entry remains available.
- If query fails, show non-blocking error and keep manual ride entry usable.
- If rider has fewer than 5 valid distinct patterns, return only available options.
90 changes: 90 additions & 0 deletions specs/008-quick-ride-entry/plan.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,90 @@
# Implementation Plan: Quick Ride Entry from Past Rides

**Branch**: `008-quick-ride-entry` | **Date**: 2026-03-30 | **Spec**: `/specs/008-quick-ride-entry/spec.md`
**Input**: Feature specification from `/specs/008-quick-ride-entry/spec.md`

**Note**: This template is filled in by the `/speckit.plan` command. See `.specify/templates/plan-template.md` for the execution workflow.

## Summary

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.

## Technical Context

**Language/Version**: C# (.NET 10), TypeScript (React 19 + Vite), F# domain project available
**Primary Dependencies**: ASP.NET Core Minimal API, EF Core (SQLite provider), existing rides endpoints and auth/session flow, React form state patterns
**Storage**: SQLite local-file profile via EF Core; quick options derived from existing rider ride data (no new storage engine)
**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
**Target Platform**: Local-first Aspire web app in DevContainer (browser frontend + .NET API)
**Project Type**: Web application (React frontend + Minimal API backend)
**Performance Goals**: Quick-options query should stay under constitutional API target (<500ms p95); quick option selection should prefill form immediately on client interaction
**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
**Scale/Scope**: One query endpoint for quick options, ride-entry UI enhancement, and tests covering duplicate suppression, limit behavior, and edit-after-prefill

## Constitution Check

*GATE: Must pass before Phase 0 research. Re-check after Phase 1 design.*

### Pre-Research Gate Review

| Gate | Status | Notes |
|------|--------|-------|
| DevContainer-only development | PASS | Planning commands and artifact generation executed inside the workspace container. |
| Clean architecture boundaries | PASS | Feature boundaries remain in ride-entry UI + API query service over existing ride data. |
| React + TypeScript consistency | PASS | Quick options rendered and applied through typed React state/form patterns. |
| Data validation depth | PASS | Existing client/API/DB validation retained; quick options only prefill values, not bypass rules. |
| Contract-first collaboration | PASS | Dedicated quick-options API contract defined before implementation. |
| TDD gated workflow | PASS WITH ACTION | Tasks must enforce red-first tests and explicit user confirmation of failing tests prior to coding. |
| Performance and observability expectations | PASS | Query limited to 5 distinct values and rider-scoped filter; metrics/logging remain on current pipeline. |

No constitutional violations identified.

### Post-Design Gate Re-Check

| Gate | Status | Notes |
|------|--------|-------|
| Architecture and modularity | PASS | Design isolates quick-option derivation in query path and keeps create-ride command flow unchanged. |
| Contract compatibility | PASS | New endpoint is additive and does not alter existing ride history or record-ride contract behavior. |
| Validation and safety | PASS | Prefill can be edited and still must pass existing required-field/constraint validation. |
| UX consistency and accessibility | PASS | Feature remains optional, non-blocking, and compatible with existing entry form behavior. |
| Verification matrix coverage | PASS WITH ACTION | Quickstart includes required backend/frontend/e2e validation commands for cross-layer changes. |

## Project Structure

### Documentation (this feature)

```text
specs/008-quick-ride-entry/
├── plan.md
├── research.md
├── data-model.md
├── quickstart.md
├── contracts/
│ └── quick-ride-options-api.yaml
└── tasks.md # generated by /speckit.tasks
```

### Source Code (repository root)
```text
src/
├── BikeTracking.Api/
│ ├── Endpoints/
│ ├── Application/
│ ├── Contracts/
│ └── Infrastructure/
├── BikeTracking.Api.Tests/
│ ├── Endpoints/
│ ├── Application/
│ └── Infrastructure/
└── BikeTracking.Frontend/
├── src/
│ ├── pages/
│ ├── components/
│ └── services/
└── tests/
```

**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.

## Complexity Tracking
No constitutional violations requiring justification.
Loading
Loading