Fix all OpenSpec validation failures (36/36 passing)

- Add ## Purpose sections and convert delta headers to ## Requirements
  on all 25 specs
- Add SHALL keywords to requirements missing them (gpx-import,
  planner-session, planner-journal-handoff)
- Convert prose GPX format section to proper scenarios (no-go-areas)
- Create specs/ delta files for 7 changes that were missing them
  (activity-photos, local-dev-stack, multi-day-routes, route-discovery,
  route-sharing, visual-redesign, waypoint-notes)

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
Ullrich Schäfer 2026-04-06 22:17:52 +02:00
parent c6949e9490
commit 0b9b99984e
32 changed files with 414 additions and 35 deletions

View file

@ -1,4 +1,8 @@
## MODIFIED Requirements
## Purpose
User account settings page with connected services management, profile editing, and security controls.
## Requirements
### Requirement: Connected Services section
The settings page SHALL include a "Connected Services" section for managing external integrations.

View file

@ -1,4 +1,8 @@
## ADDED Requirements
## Purpose
Activity creation, chronological feed, detail views, and route linking in the Journal app.
## Requirements
### Requirement: Create activity
The Journal SHALL allow authenticated users to create an activity by uploading a GPX trace and adding a description.

View file

@ -1,4 +1,8 @@
## ADDED Requirements
## Purpose
Route computation between waypoints via the BRouter HTTP API, including routing host election, result broadcasting via Yjs, profile selection, and rate-limited proxying.
## Requirements
### Requirement: Route computation from waypoints
The Planner SHALL compute a route between ordered waypoints by calling the BRouter HTTP API with tiledesc enabled and returning the result as an EnrichedRoute, preserving per-point elevation, surface data, and segment boundary indices.

View file

@ -1,3 +1,7 @@
## Purpose
Browser crash resilience via localStorage-based Yjs state persistence and recovery on reconnect.
## Requirements
### Requirement: localStorage crash recovery

View file

@ -1,4 +1,8 @@
## ADDED Requirements
## Purpose
GPX file import in the Planner via home page file picker and in-session drag-and-drop, with client-side parsing and waypoint extraction.
## Requirements
### Requirement: Import GPX from home page
Users SHALL be able to import a GPX file from the planner home page to start a new planning session.
@ -30,7 +34,9 @@ Users SHALL be able to drag a GPX file onto the map in an existing session.
- **WHEN** a user drops a GPX file and the confirmation dialog appears
- **THEN** clicking "Cancel" leaves the session unchanged
### Requirement: Non-GPX files are rejected
### Requirement: Non-GPX file rejection
The Planner SHALL reject non-GPX files dropped on the map.
#### Scenario: Drop non-GPX file
- **WHEN** a user drops a non-GPX file on the map
- **THEN** the file is ignored with a brief error toast

View file

@ -1,4 +1,8 @@
## ADDED Requirements
## Purpose
Server provisioning on Hetzner, Docker Compose deployment, CI/CD pipelines, database and BRouter management, TLS, Sentry, Grafana, and monitoring stack for the flagship instance.
## Requirements
### Requirement: Terraform Hetzner provisioning
Infrastructure SHALL be provisioned on Hetzner Cloud using Terraform with the Hetzner provider.

View file

@ -1,4 +1,8 @@
## MODIFIED Requirements
## Purpose
Authentication for the Journal app, including OAuth token storage for external services in the sync_connections table.
## Requirements
### Requirement: Store external service tokens
The journal auth system SHALL store OAuth tokens for external services alongside user credentials.

View file

@ -1,4 +1,8 @@
## ADDED Requirements
## Purpose
One-command local development setup with PostgreSQL, BRouter, automatic schema migration, and segment downloading.
## Requirements
### Requirement: One-command dev startup
The project SHALL provide a single command that starts all services needed for local development.

View file

@ -1,4 +1,8 @@
## ADDED Requirements
## Purpose
Interactive map rendering with Leaflet and OSM tiles, waypoint editing, route visualization, elevation profiles, multiplayer cursors, and polygon drawing for both Planner and Journal apps.
## Requirements
### Requirement: Map rendering with OSM tiles
The Planner and Journal SHALL render interactive maps using Leaflet with OpenStreetMap tiles as the default base layer.

View file

@ -1,3 +1,7 @@
## Purpose
Polygon-based route avoidance areas drawn on the map, synced via Yjs, sent to BRouter as constraints, and persisted in GPX extensions.
## Requirements
### Requirement: Draw no-go areas
@ -35,22 +39,16 @@ No-go areas SHALL be preserved when saving to the journal or exporting a plan.
- **AND** the file is compatible with any GPX-consuming application
### Requirement: GPX extensions format
No-go areas are stored in GPX using a custom XML namespace:
No-go areas SHALL be stored in GPX using the `trails:planning` custom XML namespace with point-based polygon representation.
```xml
<gpx xmlns:trails="https://trails.cool/gpx/1">
<extensions>
<trails:planning>
<trails:nogo>
<trails:point lat="52.5" lon="13.3"/>
<trails:point lat="52.4" lon="13.4"/>
<trails:point lat="52.3" lon="13.2"/>
</trails:nogo>
</trails:planning>
</extensions>
</gpx>
```
#### Scenario: Valid no-go area in GPX
- **WHEN** a GPX file contains a `<trails:nogo>` element with 3+ `<trails:point>` child elements
- **THEN** the parser creates a no-go area polygon from the point coordinates
- Each `<trails:nogo>` element contains 3+ `<trails:point>` elements
- Parser accepts both namespaced (`trails:nogo`) and non-namespaced (`nogo`) elements
- Areas with fewer than 3 points are rejected on parse
#### Scenario: Namespace-agnostic parsing
- **WHEN** a GPX file contains non-namespaced `<nogo>` elements instead of `<trails:nogo>`
- **THEN** the parser accepts them identically
#### Scenario: Invalid no-go area rejected
- **WHEN** a GPX file contains a no-go area with fewer than 3 points
- **THEN** the parser rejects it

View file

@ -1,3 +1,7 @@
## Purpose
Health endpoints, Prometheus metrics, structured logging, Grafana dashboards, and alerting for both apps and the flagship instance.
## Requirements
### Requirement: Health endpoints

View file

@ -1,7 +1,11 @@
## MODIFIED Requirements
## Purpose
Round-trip GPX exchange between Planner and Journal, including JWT-scoped callbacks for saving routes and GPX reimport in the Planner.
## Requirements
### Requirement: Export Plan reimport
The "Export Plan" GPX can now be reimported directly in the planner via the file upload UI, completing the round-trip without needing the journal.
The Planner SHALL support reimporting an exported plan GPX via the file upload UI, completing the round-trip without needing the journal.
#### Scenario: Reimport exported plan
- **WHEN** a user exports a plan and later imports it via the planner's GPX upload

View file

@ -1,7 +1,11 @@
## MODIFIED Requirements
## Purpose
### Requirement: Session initialization
Sessions can now be initialized from a GPX file upload in addition to URL parameters and the journal handoff.
Collaborative planning session management with Yjs CRDT synchronization, supporting initialization from URL parameters, journal handoff, and GPX file upload.
## Requirements
### Requirement: Session initialization from GPX
The Planner SHALL support initializing sessions from a GPX file upload in addition to URL parameters and the journal handoff.
#### Scenario: Session created from GPX upload
- **WHEN** a session is created via GPX file upload on the home page

View file

@ -1,3 +1,7 @@
## Purpose
Request rate limiting for Planner session creation and BRouter API calls to prevent abuse.
## Requirements
### Requirement: Session creation rate limit

View file

@ -1,3 +1,7 @@
## Purpose
Multi-mode route visualization (plain, elevation gradient, surface type) with session-synced color mode selection.
## Requirements
### Requirement: Route color modes

View file

@ -1,3 +1,7 @@
## Purpose
Ghost marker drag interaction for reshaping routes by inserting new waypoints mid-segment.
## Requirements
### Requirement: Ghost marker on route hover

View file

@ -1,4 +1,8 @@
## ADDED Requirements
## Purpose
Route CRUD operations, GPX import/export, sequential versioning, PostGIS spatial storage, and route metadata in the Journal app.
## Requirements
### Requirement: Create route
The Journal SHALL allow authenticated users to create a new route with a name and optional description.

View file

@ -1,4 +1,8 @@
## ADDED Requirements
## Purpose
Map thumbnails on route and activity list pages, and interactive maps with zoom and layer switching on detail pages.
## Requirements
### Requirement: Route map preview on list pages
Route and activity list pages SHALL show a small map thumbnail for each item that has geometry.

View file

@ -1,3 +1,7 @@
## Purpose
Waypoint insertion by clicking the ghost marker on the route polyline, splitting a segment into two.
## Requirements
### Requirement: Insert waypoint by clicking on route

View file

@ -1,3 +1,7 @@
## Purpose
SOPS-encrypted secrets stored in the repository, split into app and infra files, decryptable with a single age key at deploy time.
## Requirements
### Requirement: Encrypted secrets in repository

View file

@ -1,3 +1,7 @@
## Purpose
Security headers, scanner path blocking, secret scanning, dependency auditing, non-root containers, and vulnerability disclosure policy.
## Requirements
### Requirement: Security response headers

View file

@ -1,3 +1,7 @@
## Purpose
Collaborative text notes in Planner sessions, synced in real-time via Yjs.
## Requirements
### Requirement: Collaborative session notes

View file

@ -1,4 +1,8 @@
## ADDED Requirements
## Purpose
Shared TypeScript packages (@trails-cool/types, gpx, map, ui, i18n) used by both Planner and Journal apps.
## Requirements
### Requirement: Shared types package
The `@trails-cool/types` package SHALL export TypeScript interfaces for Route, Activity, Waypoint, RouteVersion, and RouteMetadata used by both apps.

View file

@ -1,3 +1,7 @@
## Purpose
Transactional email sending with HTML and plain-text templates for magic links and welcome messages, using SMTP in production and console logging in dev.
## Requirements
### Requirement: Email sending interface

View file

@ -1,4 +1,8 @@
## ADDED Requirements
## Purpose
Provider-agnostic activity sync framework with Wahoo as the first provider, supporting OAuth connection, webhook-based automatic sync, manual import, and FIT-to-GPX conversion.
## Requirements
### Requirement: Provider-agnostic sync framework
The system SHALL provide a common interface for external activity sync providers.