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>
74 lines
2.7 KiB
Markdown
74 lines
2.7 KiB
Markdown
## Context
|
|
|
|
The Planner architecture defines noGoAreas, notes, and crash recovery in the
|
|
Yjs data model but none are implemented. The public instance also lacks rate
|
|
limiting — anyone can create unlimited sessions or hammer BRouter.
|
|
|
|
## Goals / Non-Goals
|
|
|
|
**Goals:**
|
|
- Draw no-go polygons on the map, synced via Yjs, sent to BRouter
|
|
- Shared notes (Y.Text) visible in sidebar for planning discussion
|
|
- localStorage backup of Yjs state, merged on reconnect
|
|
- Rate limits: 10 sessions/IP/hour, 60 BRouter calls/session/hour
|
|
|
|
**Non-Goals:**
|
|
- Complex polygon editing (holes, multi-polygon) — just simple polygons
|
|
- Rich text in notes (just plain text)
|
|
- Cross-tab Yjs sync via localStorage (handled by WebSocket)
|
|
- Rate limiting dashboard or admin UI
|
|
|
|
## Decisions
|
|
|
|
### D1: No-go areas as Yjs Y.Array of polygon coordinates
|
|
|
|
```typescript
|
|
// Yjs doc structure addition
|
|
noGoAreas: Y.Array<Y.Map<{
|
|
points: Array<{lat: number, lon: number}>,
|
|
name?: string
|
|
}>>
|
|
```
|
|
|
|
Each polygon is a closed ring of lat/lon points. BRouter accepts no-go areas
|
|
as a `nogo` parameter: `lon,lat,radius` for circles or polygon coordinates
|
|
depending on the BRouter version. We'll convert our polygons to BRouter's
|
|
expected format in the routing request.
|
|
|
|
### D2: Leaflet.draw for polygon drawing
|
|
|
|
Use `leaflet-draw` (or `@geoman-io/leaflet-geoman-free`) for drawing polygons
|
|
on the map. When a polygon is completed, add it to the Y.Array. Existing
|
|
polygons render as semi-transparent red overlays.
|
|
|
|
### D3: Notes as Y.Text in sidebar tab
|
|
|
|
Add a "Notes" tab to the sidebar (alongside waypoints). Uses Y.Text for
|
|
collaborative editing — simple textarea bound to Y.Text. Changes sync in
|
|
real-time. No markdown rendering — plain text only.
|
|
|
|
### D4: localStorage crash recovery
|
|
|
|
Every 10 seconds, save `Y.encodeStateAsUpdate(doc)` to
|
|
`localStorage['trails:session:${id}']`. On page load, if localStorage has
|
|
state for the current session, apply it as an update before connecting to
|
|
the server. Yjs CRDTs merge automatically — no conflicts.
|
|
|
|
Clear localStorage entry when session is closed or after successful sync.
|
|
|
|
### D5: In-memory rate limiter
|
|
|
|
Simple Map-based rate limiter in `server.ts`:
|
|
- Session creation: Track IP → count + window. Reject with 429 after 10/hour.
|
|
- BRouter proxy: Track session ID → count + window. Reject after 60/hour.
|
|
- No Redis needed — single server, in-memory is fine. Resets on restart
|
|
(acceptable).
|
|
|
|
## Risks / Trade-offs
|
|
|
|
- **leaflet-draw adds bundle size** → ~50KB gzipped. Acceptable for polygon
|
|
drawing functionality. Can lazy-load.
|
|
- **localStorage size limit** → ~5MB per origin. Yjs state is typically
|
|
10-100KB. No risk.
|
|
- **In-memory rate limiter resets on deploy** → Acceptable for current scale.
|
|
Redis-backed when needed.
|