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
2 changes: 1 addition & 1 deletion .specify/feature.json
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
{
"feature_directory": "specs/020-improve-ride-preset-options"
"feature_directory": "specs/022-pwa-local-install"
}
35 changes: 35 additions & 0 deletions specs/022-pwa-local-install/checklists/requirements.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
# Specification Quality Checklist: Local PWA Installation

**Purpose**: Validate specification completeness and quality before proceeding to planning
**Created**: 2026-05-20
**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: all checklist items currently pass.
- No unresolved clarification markers remain.
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
# Contract: PWA Installation and Runtime Behavior

**Feature**: 022-pwa-local-install
**Type**: Frontend/platform behavior contract
**Status**: Draft

## 1. Supported Environment Contract (v1)

Install support is guaranteed only when all conditions are true:

- Operating system: Windows desktop
- Browser family: current Chrome or current Edge
- Browser install prerequisites: satisfied for the running app

If any condition is false, app must:

- Keep core browser usage available
- Show explicit guidance that installed-app support is unavailable in v1

## 2. Install Interaction Contract

When install is supported and prompt is available:

- App exposes a visible install action
- Install action triggers browser-native install flow
- On success, app can be launched from OS app launcher and opens in app-style window

Failure handling:

- On prompt dismissal or install failure, app shows non-blocking guidance and allows retry

## 3. Online-Only Operations Contract

For v1 installed mode:

- Ride operations require network connectivity
- If offline, app shows connectivity-required guidance and retry path
- App remains stable and navigable while operations are blocked

## 4. Update Lifecycle Contract

Installed app update behavior:

- Checks for updates on relaunch or refresh
- Applies latest available version automatically when available
- Exposes user-facing status for update in-progress and update failure states

State model:

- `idle -> checking -> downloading -> ready -> applied`
- Failure path: `checking/downloading -> failed`

## 5. Session Persistence Contract

Authentication behavior in installed mode:

- Session persists across launches up to 7 days inactivity
- Explicit sign-out immediately invalidates session
- On inactivity > 7 days, app requires sign-in before authenticated ride operations

## 6. Backend API Contract Impact

No mandatory API schema changes are introduced by this feature contract.

If implementation discovers backend compatibility needs for session timeout semantics, any API changes must be additive and documented in a follow-up contract update.
105 changes: 105 additions & 0 deletions specs/022-pwa-local-install/data-model.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,105 @@
# Data Model: Local PWA Installation

**Feature**: 022-pwa-local-install
**Date**: 2026-05-20
**Status**: Complete

## Overview

This feature introduces client-side runtime state models for installability, launch context, update lifecycle, and 7-day inactivity session timeout. No new server database entities are required for v1.

## Entities

### 1. InstallationState

Represents install capability and install progression for the current environment.

| Field | Type | Description |
|------|------|-------------|
| `isInstallSupported` | boolean | Whether current browser+OS matches v1 support matrix and install prerequisites are satisfied |
| `installPromptAvailable` | boolean | Whether install prompt can be triggered in current session |
| `status` | enum | `unavailable` \| `available` \| `prompting` \| `installed` \| `failed` |
| `reasonCode` | enum? | Optional code for unavailable/failed states (`unsupported_os`, `unsupported_browser`, `prompt_dismissed`, `policy_blocked`) |
| `lastTransitionAtUtc` | string (ISO-8601) | Timestamp for diagnostics and telemetry correlation |

**Validation rules**:
- `status=installed` implies `isInstallSupported=true`.
- `reasonCode` required when `status` is `unavailable` or `failed`.

### 2. LaunchContext

Represents app runtime context at startup.

| Field | Type | Description |
|------|------|-------------|
| `mode` | enum | `browser_tab` \| `installed_window` |
| `isOnline` | boolean | Network availability at startup |
| `platform` | enum | `windows` \| `non_windows` |
| `browserFamily` | enum | `chrome` \| `edge` \| `other` |
| `appVersion` | string | Current loaded app version identifier |

**Validation rules**:
- `mode=installed_window` only valid when install criteria were previously met.
- `platform=non_windows` forces `InstallationState.status=unavailable` for v1 support policy.

### 3. SessionState

Represents authenticated state persistence across launches with inactivity expiration.

| Field | Type | Description |
|------|------|-------------|
| `isAuthenticated` | boolean | Rider is currently authenticated |
| `lastActivityAtUtc` | string (ISO-8601) | Last authenticated user activity timestamp |
| `expiresAtUtc` | string (ISO-8601) | Computed expiration timestamp (`lastActivityAtUtc + 7 days`) |
| `expiredByInactivity` | boolean | True when reopening after expiration threshold |

**Validation rules**:
- When `nowUtc > expiresAtUtc`, app must set `isAuthenticated=false` and require sign-in.
- Explicit sign-out invalidates session regardless of inactivity timer.

### 4. UpdateState

Represents automatic update lifecycle for installed instances.

| Field | Type | Description |
|------|------|-------------|
| `status` | enum | `idle` \| `checking` \| `downloading` \| `ready` \| `applied` \| `failed` |
| `targetVersion` | string? | Version being applied |
| `lastCheckedAtUtc` | string (ISO-8601) | Last update check timestamp |
| `failureReason` | string? | Optional failure message for user guidance |

**Validation rules**:
- `failureReason` required when `status=failed`.
- Transition `ready -> applied` occurs on relaunch or refresh.

## State Transitions

### InstallationState transitions

`unavailable -> available -> prompting -> installed`

Failure path:

`available -> prompting -> failed -> available`

### SessionState transitions

`authenticated(active) -> authenticated(inactive) -> expiredByInactivity -> unauthenticated`

Sign-out path:

`authenticated -> unauthenticated`

### UpdateState transitions

`idle -> checking -> downloading -> ready -> applied`

Failure path:

`checking/downloading -> failed -> checking`

## Persistence Notes

- `SessionState` persistence must survive installed-app relaunches.
- `InstallationState`, `LaunchContext`, and `UpdateState` are runtime and telemetry-oriented state; persistence can be ephemeral unless needed for diagnostics.
- Domain data (rides, users, projections) remains in existing SQLite storage and is unchanged by this feature.
87 changes: 87 additions & 0 deletions specs/022-pwa-local-install/plan.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,87 @@
# Implementation Plan: Local PWA Installation

**Branch**: `022-pwa-local-install` | **Date**: 2026-05-20 | **Spec**: [spec.md](./spec.md)
**Input**: Feature specification from `/specs/022-pwa-local-install/spec.md`

## Summary

Enable local desktop installation for Bike Tracking as a PWA on Windows (Chrome/Edge), with
online-only ride operations in v1, automatic app updates on relaunch/refresh, and persisted sign-in
for up to 7 days of inactivity. Implementation centers on frontend PWA enablement (manifest,
service worker lifecycle, install UX), plus authentication session persistence policy updates and
clear unsupported-environment messaging.

## Technical Context

**Language/Version**: C# .NET 10 (API), F# .NET 10 (domain unchanged), TypeScript + React 19 (frontend)
**Primary Dependencies**: ASP.NET Core Minimal API, EF Core SQLite, Aspire, React 19 + Vite, browser PWA capabilities
**Storage**: SQLite local file for domain data; browser local storage/session storage for client auth/session metadata
**Testing**: xUnit (backend), Vitest (frontend), Playwright (E2E)
**Target Platform**: Windows desktop end-user machines; Chrome and Edge for supported install flows
**Project Type**: Local-first web application (Aspire orchestrated API + frontend)
**Performance Goals**: Preserve existing API goal (<500ms p95 normal operations); install affordance visible within 1s of app boot; session rehydrate <300ms on launch
**Constraints**: v1 online-only for ride operations; Windows-only install support; auto-update on relaunch/refresh; re-auth required after 7 days inactivity
**Scale/Scope**: Single-user local deployment; one installable shell for existing ride tracking flows; no new backend aggregate introduced

## Constitution Check

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

| Gate | Status | Notes |
|------|--------|-------|
| Clean Architecture / Ports-and-Adapters | PASS | PWA/browser APIs isolated in frontend adapter layer; no domain leakage |
| Functional Core / Impure Edges | PASS | Feature is primarily UI/runtime behavior; domain logic remains unchanged |
| Event Sourcing / CQRS | PASS | No changes to event schema required for v1 install capability |
| TDD Red-Green-Refactor | PASS | quickstart defines red tests first for install, session timeout, unsupported environments |
| UX Consistency / Accessibility | PASS | Install guidance and unsupported-environment messaging must remain accessible and keyboard navigable |
| Performance / Observability | PASS | No heavy runtime background work; retain API latency and add client install/update telemetry events |
| Data Validation / Integrity | PASS | Existing server validations unchanged; client session timeout state validated by deterministic timestamp checks |
| Security / Learning | PASS | 7-day inactivity sign-in policy limits stale auth risk; no secrets added to client assets |
| Modularity / Contract-First | PASS | PWA capability contract documented in `contracts/pwa-installation-contract.md` |
| Trunk-Based Delivery / CI | PASS | No branch strategy changes; full CI matrix remains required |

**Post-Design Constitution Re-check**: PASS. Phase 1 artifacts keep changes modular in frontend infrastructure (`src/BikeTracking.Frontend`) and avoid domain/event-store coupling.

## Project Structure

### Documentation (this feature)

```text
specs/022-pwa-local-install/
├── plan.md
├── research.md
├── data-model.md
├── quickstart.md
├── contracts/
│ └── pwa-installation-contract.md
└── tasks.md
```

### Source Code (repository root)

```text
src/
├── BikeTracking.Api/
│ ├── Program.cs
│ ├── Application/
│ ├── Contracts/
│ └── Infrastructure/
├── BikeTracking.Api.Tests/
├── BikeTracking.Domain.FSharp/
├── BikeTracking.Frontend/
│ ├── public/
│ ├── src/
│ │ ├── components/
│ │ ├── pages/
│ │ ├── services/
│ │ └── main.tsx
│ ├── vite.config.ts
│ └── package.json
└── BikeTracking.AppHost/
```

**Structure Decision**: Keep existing Aspire web application layout. Implement PWA install/update/session behavior inside `src/BikeTracking.Frontend` with minimal backend touch points only if auth-token semantics require API contract alignment.

## Complexity Tracking

No constitutional violations requiring justification.
Loading
Loading