Add 8 proposed changes and old trails analysis
Proposed changes (all with proposal, design, specs, tasks): - app-navigation (9 tasks) — nav bars for both apps - planner-landing-page (7 tasks) — standalone landing page - planner-multiplayer-awareness (13 tasks) — participants, cursors, names - changelog (13 tasks) — public changelog with "what's new" - transactional-emails (15 tasks) — magic link + welcome emails - planner-features (18 tasks) — no-go areas, notes, recovery, rate limits - komoot-import (23 tasks) — Komoot tour import - route-features (37 tasks) — sharing, multi-day, spatial, photos Also adds docs/old-trails-analysis.md with feature analysis from the older trails project. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
parent
57141cdfab
commit
c7c1c275df
55 changed files with 1704 additions and 0 deletions
2
openspec/changes/route-features/.openspec.yaml
Normal file
2
openspec/changes/route-features/.openspec.yaml
Normal file
|
|
@ -0,0 +1,2 @@
|
|||
schema: spec-driven
|
||||
created: 2026-03-25
|
||||
71
openspec/changes/route-features/design.md
Normal file
71
openspec/changes/route-features/design.md
Normal file
|
|
@ -0,0 +1,71 @@
|
|||
## Context
|
||||
|
||||
The architecture doc defines a rich route model with permissions, multi-day
|
||||
support, spatial queries, and photos. Currently routes are owner-only, flat
|
||||
(no days), and have no photos or spatial search. This change adds the route
|
||||
and activity features needed before federation makes them visible to others.
|
||||
|
||||
## Goals / Non-Goals
|
||||
|
||||
**Goals:**
|
||||
- Route visibility (private/public) and sharing with specific users
|
||||
- Fork public routes
|
||||
- Multi-day route support with day-break waypoints
|
||||
- Map-based route discovery via PostGIS
|
||||
- Photo attachments on activities
|
||||
- Contributor tracking on route versions
|
||||
|
||||
**Non-Goals:**
|
||||
- Federation of routes (separate change)
|
||||
- Real-time collaborative permission changes
|
||||
- Photo editing or filters
|
||||
- Route recommendations based on preferences
|
||||
- Activity collections (multi-day trip grouping — future)
|
||||
|
||||
## Decisions
|
||||
|
||||
### D1: Visibility as enum column on routes and activities
|
||||
|
||||
Add `visibility` column (`public`, `private`, default `private`) to both
|
||||
routes and activities. `followers_only` added later when following exists.
|
||||
Public routes appear in spatial search. Private routes are owner-only.
|
||||
|
||||
### D2: Route shares table for explicit sharing
|
||||
|
||||
```
|
||||
journal.route_shares (routeId, userId, permission: 'view' | 'edit')
|
||||
```
|
||||
|
||||
Owner can share with specific users. Shared users see the route in their
|
||||
"Shared with me" section. Edit permission allows starting Planner sessions.
|
||||
|
||||
### D3: Day breaks as waypoint property
|
||||
|
||||
The Planner's Yjs waypoint Y.Map gets an optional `isDayBreak: true` field.
|
||||
The sidebar and elevation chart show day boundaries. GPX export uses one
|
||||
track segment per day. The Journal stores day-break indices in route metadata.
|
||||
|
||||
### D4: PostGIS spatial search
|
||||
|
||||
Routes already store geometry as PostGIS LineString. Add a `/routes/explore`
|
||||
page with a map — as the user pans/zooms, query public routes within the
|
||||
bounding box using `ST_Intersects`. Show route previews on the map.
|
||||
|
||||
### D5: Photo storage via S3 (Garage)
|
||||
|
||||
Use the Garage S3-compatible storage already in the architecture. Upload flow:
|
||||
server generates presigned PUT URL → client uploads directly to S3 → server
|
||||
stores the S3 key in a `journal.activity_photos` table. Serve via presigned
|
||||
GET URLs or a CDN path.
|
||||
|
||||
### D6: Contributor tracking via array column
|
||||
|
||||
Add `contributors` text array to `journal.route_versions`. When a Planner
|
||||
session saves back via callback, the JWT identifies the actor. The version
|
||||
records the contributor's user ID (or ActivityPub URI for future federation).
|
||||
|
||||
## Risks / Trade-offs
|
||||
|
||||
- **S3 setup required** → Garage needs to be enabled in docker-compose (currently commented out). Adds operational complexity.
|
||||
- **Spatial search performance** → PostGIS bounding box queries are fast with spatial indexes. Already have the geometry column.
|
||||
- **Multi-day in Planner requires Yjs changes** → Adding `isDayBreak` to waypoints is backward-compatible (optional field). Existing sessions unaffected.
|
||||
43
openspec/changes/route-features/proposal.md
Normal file
43
openspec/changes/route-features/proposal.md
Normal file
|
|
@ -0,0 +1,43 @@
|
|||
## Why
|
||||
|
||||
Routes are currently flat — no permissions beyond owner, no way to share with
|
||||
specific people, no forking, no multi-day support, no spatial discovery, and
|
||||
no contributor tracking. The architecture doc specifies all of these for Phase
|
||||
2. Without them, routes are just personal GPX storage with no social or
|
||||
collaborative dimension.
|
||||
|
||||
## What Changes
|
||||
|
||||
- **Route sharing permissions**: Private/public/shared visibility levels with
|
||||
a view/edit permission matrix
|
||||
- **Route forking**: Copy someone else's public route to your own collection
|
||||
- **Multi-day routes**: Day-break waypoints that split a route into stages with
|
||||
per-day stats and GPX segments
|
||||
- **Spatial search**: "Routes near me" or "routes in this area" using PostGIS
|
||||
- **Contributor tracking**: Record who contributed to each route version
|
||||
- **Activity visibility levels**: Public/followers-only/private on activities
|
||||
- **Photo attachments**: Upload photos to activities (requires S3/Garage setup)
|
||||
|
||||
## Capabilities
|
||||
|
||||
### New Capabilities
|
||||
|
||||
- `route-sharing`: Permission model (private/public/shared), view/edit access, route forking
|
||||
- `spatial-search`: Map-based route discovery using PostGIS bounding box and proximity queries
|
||||
- `multi-day-routes`: Day-break markers on waypoints, per-day stats, multi-segment GPX export
|
||||
- `activity-photos`: Photo upload and display on activities via S3-compatible storage
|
||||
|
||||
### Modified Capabilities
|
||||
|
||||
- `route-management`: Add visibility, contributor tracking, forking
|
||||
- `activity-feed`: Add visibility levels (public/followers-only/private)
|
||||
- `planner-session`: Support day-break waypoint markers
|
||||
- `infrastructure`: S3/Garage setup for photo storage
|
||||
|
||||
## Impact
|
||||
|
||||
- **Database**: New columns (visibility, contributors) on routes and activities, new route_shares table, photo storage metadata
|
||||
- **Storage**: S3-compatible object storage (Garage) for photos
|
||||
- **Files**: Route detail page, activity pages, search page, Planner waypoint UI, sharing UI
|
||||
- **Dependencies**: S3 client library for photo uploads
|
||||
- **Privacy**: Photo storage, route visibility controls documented in manifest
|
||||
12
openspec/changes/route-features/specs/activity-feed/spec.md
Normal file
12
openspec/changes/route-features/specs/activity-feed/spec.md
Normal file
|
|
@ -0,0 +1,12 @@
|
|||
## MODIFIED Requirements
|
||||
|
||||
### Requirement: Activity visibility
|
||||
Activities SHALL have visibility levels controlling who can see them.
|
||||
|
||||
#### Scenario: Private activity
|
||||
- **WHEN** an activity's visibility is "private"
|
||||
- **THEN** only the owner can view it
|
||||
|
||||
#### Scenario: Public activity
|
||||
- **WHEN** an activity's visibility is "public"
|
||||
- **THEN** anyone can view it on the owner's profile
|
||||
|
|
@ -0,0 +1,16 @@
|
|||
## ADDED Requirements
|
||||
|
||||
### Requirement: Photo attachments on activities
|
||||
Users SHALL be able to upload photos to their activities.
|
||||
|
||||
#### Scenario: Upload photo
|
||||
- **WHEN** a user adds a photo to an activity
|
||||
- **THEN** the photo is uploaded to S3 storage and linked to the activity
|
||||
|
||||
#### Scenario: View photos
|
||||
- **WHEN** a user views an activity with photos
|
||||
- **THEN** the photos are displayed in a gallery on the activity page
|
||||
|
||||
#### Scenario: Delete photo
|
||||
- **WHEN** a user deletes a photo from their activity
|
||||
- **THEN** the photo is removed from storage and unlinked
|
||||
|
|
@ -0,0 +1,16 @@
|
|||
## ADDED Requirements
|
||||
|
||||
### Requirement: Day-break waypoints
|
||||
Waypoints in the Planner SHALL support a day-break marker that splits the route into stages.
|
||||
|
||||
#### Scenario: Mark day break
|
||||
- **WHEN** a user marks a waypoint as a day break in the Planner
|
||||
- **THEN** the route is visually split into days at that point
|
||||
|
||||
#### Scenario: Per-day statistics
|
||||
- **WHEN** a route has day-break markers
|
||||
- **THEN** the sidebar shows distance and elevation per day/stage
|
||||
|
||||
#### Scenario: GPX export with day segments
|
||||
- **WHEN** a multi-day route is exported as GPX
|
||||
- **THEN** each day is a separate track segment in the GPX file
|
||||
|
|
@ -0,0 +1,12 @@
|
|||
## MODIFIED Requirements
|
||||
|
||||
### Requirement: Route metadata
|
||||
Routes SHALL track visibility, contributors, and support forking.
|
||||
|
||||
#### Scenario: Visibility on route creation
|
||||
- **WHEN** a user creates a route
|
||||
- **THEN** the route defaults to "private" visibility
|
||||
|
||||
#### Scenario: Contributor recorded on version
|
||||
- **WHEN** a Planner session saves a new route version via callback
|
||||
- **THEN** the version records the contributor who made the edit
|
||||
30
openspec/changes/route-features/specs/route-sharing/spec.md
Normal file
30
openspec/changes/route-features/specs/route-sharing/spec.md
Normal file
|
|
@ -0,0 +1,30 @@
|
|||
## ADDED Requirements
|
||||
|
||||
### Requirement: Route visibility levels
|
||||
Routes SHALL have a visibility setting controlling who can see them.
|
||||
|
||||
#### Scenario: Private route
|
||||
- **WHEN** a route's visibility is "private"
|
||||
- **THEN** only the owner can view it
|
||||
|
||||
#### Scenario: Public route
|
||||
- **WHEN** a route's visibility is "public"
|
||||
- **THEN** anyone can view it and export its GPX
|
||||
|
||||
### Requirement: Share routes with specific users
|
||||
Route owners SHALL be able to share routes with specific users at view or edit permission levels.
|
||||
|
||||
#### Scenario: Share with view access
|
||||
- **WHEN** owner shares a route with another user as "view"
|
||||
- **THEN** that user can see the route and export GPX but cannot edit
|
||||
|
||||
#### Scenario: Share with edit access
|
||||
- **WHEN** owner shares a route with another user as "edit"
|
||||
- **THEN** that user can start Planner sessions and create new versions
|
||||
|
||||
### Requirement: Fork routes
|
||||
Users SHALL be able to fork (copy) public routes to their own collection.
|
||||
|
||||
#### Scenario: Fork a public route
|
||||
- **WHEN** a user clicks "Fork" on a public route
|
||||
- **THEN** a copy is created in their collection with the original credited
|
||||
12
openspec/changes/route-features/specs/spatial-search/spec.md
Normal file
12
openspec/changes/route-features/specs/spatial-search/spec.md
Normal file
|
|
@ -0,0 +1,12 @@
|
|||
## ADDED Requirements
|
||||
|
||||
### Requirement: Map-based route discovery
|
||||
Users SHALL be able to discover public routes by browsing a map.
|
||||
|
||||
#### Scenario: Browse routes on map
|
||||
- **WHEN** a user visits the route explore page and pans/zooms the map
|
||||
- **THEN** public routes within the visible area are shown as polylines on the map
|
||||
|
||||
#### Scenario: Route preview
|
||||
- **WHEN** a user clicks a route on the explore map
|
||||
- **THEN** a popup or sidebar shows the route name, distance, elevation, and a link to the detail page
|
||||
68
openspec/changes/route-features/tasks.md
Normal file
68
openspec/changes/route-features/tasks.md
Normal file
|
|
@ -0,0 +1,68 @@
|
|||
## 1. Route Visibility & Sharing Schema
|
||||
|
||||
- [ ] 1.1 Add `visibility` enum column (private, public) to `journal.routes`, default private
|
||||
- [ ] 1.2 Add `visibility` enum column (private, public) to `journal.activities`, default private
|
||||
- [ ] 1.3 Create `journal.route_shares` table (routeId, userId, permission: view/edit)
|
||||
- [ ] 1.4 Add `contributors` text array column to `journal.route_versions`
|
||||
- [ ] 1.5 Add `forkedFromId` nullable column to `journal.routes`
|
||||
- [ ] 1.6 Push schema and verify locally
|
||||
|
||||
## 2. Route Permissions Logic
|
||||
|
||||
- [ ] 2.1 Create `apps/journal/app/lib/permissions.server.ts` with canView(routeId, userId), canEdit(routeId, userId) functions
|
||||
- [ ] 2.2 Update route detail loader to check visibility/permissions (show 404 for unauthorized)
|
||||
- [ ] 2.3 Update route list to only show own + shared routes
|
||||
- [ ] 2.4 Add visibility toggle (private/public) to route edit page
|
||||
- [ ] 2.5 Add share dialog — search users, set view/edit permission
|
||||
|
||||
## 3. Route Forking
|
||||
|
||||
- [ ] 3.1 Add "Fork" button on public route detail pages (visible to logged-in users who aren't the owner)
|
||||
- [ ] 3.2 Create fork API route — copies route + latest GPX to user's collection, sets forkedFromId
|
||||
- [ ] 3.3 Show "Forked from [original]" link on forked routes
|
||||
|
||||
## 4. Spatial Search
|
||||
|
||||
- [ ] 4.1 Ensure PostGIS spatial index exists on routes.geometry column
|
||||
- [ ] 4.2 Create `/routes/explore` route with a full-page map
|
||||
- [ ] 4.3 Add API route to query public routes within bounding box (ST_Intersects)
|
||||
- [ ] 4.4 Render matching routes as polylines on the explore map
|
||||
- [ ] 4.5 Add route popup/sidebar with name, stats, link to detail
|
||||
|
||||
## 5. Multi-Day Routes
|
||||
|
||||
- [ ] 5.1 Add `isDayBreak` optional boolean support to Planner waypoint Y.Map
|
||||
- [ ] 5.2 Add day-break toggle in Planner waypoint sidebar (click to mark/unmark)
|
||||
- [ ] 5.3 Show day boundaries in elevation chart
|
||||
- [ ] 5.4 Compute per-day distance and elevation in sidebar
|
||||
- [ ] 5.5 Update GPX export to use one track segment per day
|
||||
- [ ] 5.6 Store dayBreaks array in route metadata on save
|
||||
|
||||
## 6. Activity Photos
|
||||
|
||||
- [ ] 6.1 Enable Garage in docker-compose.yml, create bucket
|
||||
- [ ] 6.2 Create S3 client utility (`apps/journal/app/lib/storage.server.ts`) with presigned URL generation
|
||||
- [ ] 6.3 Create `journal.activity_photos` table (id, activityId, s3Key, altText, createdAt)
|
||||
- [ ] 6.4 Add photo upload UI on activity detail/edit page
|
||||
- [ ] 6.5 Display photo gallery on activity detail page
|
||||
- [ ] 6.6 Add delete photo functionality
|
||||
|
||||
## 7. Contributor Tracking
|
||||
|
||||
- [ ] 7.1 Update Planner→Journal callback to include contributor info from JWT
|
||||
- [ ] 7.2 Store contributor in route_versions on save
|
||||
- [ ] 7.3 Display contributors on route detail page
|
||||
|
||||
## 8. Privacy & i18n
|
||||
|
||||
- [ ] 8.1 Update /privacy page: document photo storage, route visibility, sharing
|
||||
- [ ] 8.2 Add i18n keys for all new UI strings (en + de)
|
||||
|
||||
## 9. Verify
|
||||
|
||||
- [ ] 9.1 Test route visibility: create private and public routes, verify access control
|
||||
- [ ] 9.2 Test sharing: share route with another user, verify view/edit access
|
||||
- [ ] 9.3 Test forking: fork a public route, verify copy created
|
||||
- [ ] 9.4 Test spatial search: create public routes, verify they appear on explore map
|
||||
- [ ] 9.5 Test multi-day: mark day breaks, verify per-day stats and GPX export
|
||||
- [ ] 9.6 Test photos: upload, view, delete photos on activities
|
||||
Loading…
Add table
Add a link
Reference in a new issue