Archive app-navigation and planner-multiplayer-awareness, sync specs

Both changes fully implemented. Sync delta specs to main:
- map-display: add Planner home page nav and cursor rendering requirements
- planner-session: add session participant awareness requirement

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
Ullrich Schäfer 2026-03-26 00:41:51 +01:00
parent 589cb4ab15
commit 538a69e1c5
No known key found for this signature in database
GPG key ID: A32FF691A0F752D9
13 changed files with 49 additions and 0 deletions

View file

@ -0,0 +1,2 @@
schema: spec-driven
created: 2026-03-25

View file

@ -0,0 +1,40 @@
## Context
Navigation audit found: Journal's `/routes` and `/activities` pages are
orphaned (no links point to them). The Planner home page has no CTA. Logout
is only on the profile page. Users must know URLs to use the apps.
## Goals / Non-Goals
**Goals:**
- Every non-API route reachable via UI navigation
- Logged-in Journal users see: Routes, Activities, profile, logout
- Logged-out Journal users see: login, register
- Planner home has a clear "start planning" action
- Keep it minimal — a thin bar, not a complex sidebar
**Non-Goals:**
- Mobile hamburger menu (responsive PR already hides sidebar — nav bar wraps naturally)
- Breadcrumbs or nested navigation
- Settings page (future)
## Decisions
### D1: Journal nav bar in root Layout
Add a `<nav>` element inside `Layout` in `root.tsx`. The root loader already
returns the user (added for Sentry context), so the nav bar can conditionally
show authenticated vs. unauthenticated links. No new loader needed.
### D2: Planner gets a CTA on home, not a nav bar
The Planner is session-focused — users arrive, create a session, and work in
it. A full nav bar would be overhead. Instead: home page gets a prominent
"Start Planning" button linking to `/new`. Session view already has a header —
add a small logo/home link to it.
### D3: Use @trails-cool/ui for shared nav component
The nav bar itself is Journal-specific (routes, activities, auth). No need
to put it in the shared UI package — it goes directly in Journal's root.tsx
or a colocated component.

View file

@ -0,0 +1,33 @@
## Why
Both apps have pages that are only reachable by typing URLs. The Journal has no
navigation bar — logged-in users can't find their routes or activities without
knowing the URLs. The Planner home page is a dead end with no way to create a
session. This makes the apps unusable for anyone who doesn't know the URL
structure.
## What Changes
- **Journal**: Add a navigation bar (home, routes, activities, profile, logout)
that appears when logged in. Unauthenticated users see login/register links.
- **Planner**: Add a "New Session" CTA on the home page. Add a minimal header
in session view with a link back to home.
- Both apps get consistent, minimal navigation that makes all features
discoverable.
## Capabilities
### New Capabilities
(None — this adds UI chrome to existing features, no new behavioral capabilities.)
### Modified Capabilities
- `map-display`: Planner home page gains a CTA and session header gains a home link
## Impact
- **Files**: Journal `root.tsx` (nav bar), Planner `home.tsx` (CTA),
Planner `SessionView.tsx` (home link), new `NavBar` component
- **Dependencies**: None
- **i18n**: New translation keys for navigation labels

View file

@ -0,0 +1,12 @@
## MODIFIED Requirements
### Requirement: Planner home page
The Planner home page SHALL provide a clear call-to-action to create a new planning session and a link back to the home page from within sessions.
#### Scenario: Home page CTA
- **WHEN** a user visits the Planner home page
- **THEN** a prominent "Start Planning" button is visible that links to `/new`
#### Scenario: Session home link
- **WHEN** a user is in a planning session
- **THEN** the header contains a link back to the Planner home page

View file

@ -0,0 +1,18 @@
## 1. Journal Navigation Bar
- [x] 1.1 Add nav bar to Journal root Layout — show "Routes", "Activities" links when logged in; "Login", "Register" when logged out
- [x] 1.2 Add user menu to nav bar — username/display name linking to profile, logout button
- [x] 1.3 Highlight active nav item based on current route
- [x] 1.4 Add i18n keys for nav labels (en + de): routes, activities, profile, logout
## 2. Planner Navigation
- [x] 2.1 Add "Start Planning" CTA button on Planner home page linking to `/new` (already done in planner-landing-page change)
- [x] 2.2 Add home link (logo or text) to SessionView header
- [x] 2.3 Add i18n keys for planner nav (en + de): startPlanning, home
## 3. Verify
- [x] 3.1 Verify all Journal routes are reachable via navigation (routes, activities, profile, auth, privacy)
- [x] 3.2 Verify Planner home → new session → back to home works
- [x] 3.3 Update E2E tests if navigation changes affect existing selectors

View file

@ -0,0 +1,2 @@
schema: spec-driven
created: 2026-03-25

View file

@ -0,0 +1,46 @@
## Context
Yjs awareness already tracks users with `{ color, name }` state and renders
map cursors via `CursorTracker` in `PlannerMap.tsx`. The current implementation
has issues: random names can't be changed, cursor labels are unstyled, and
there's no participant list showing who's in the session.
## Goals / Non-Goals
**Goals:**
- See all participants in the session (name, color, host/participant role)
- Edit your own name (saved to localStorage, synced via awareness)
- Polished cursor rendering on the map
- Visual feedback when someone joins or leaves
**Non-Goals:**
- Chat or messaging between participants
- Cursor position sharing outside the map (e.g., in the sidebar)
- Participant permissions or kicking (admin-only debug feature already exists)
## Decisions
### D1: Participant list in session header
Show colored dots + names in the header bar (already has space between profile
selector and connection status). Clicking your own name opens an inline edit.
Keeps the sidebar free for waypoints.
### D2: Name persisted in localStorage, synced via awareness
Current approach: random name from a list, stored in localStorage as
`trails:user`. Enhancement: let users edit it. On change, update localStorage
AND call `awareness.setLocalStateField("user", { color, name })`. All other
clients see the update immediately.
### D3: Cursor as SVG pointer with name tag
Replace the current `divIcon` cursor label with: a small SVG arrow in the
user's color + a name tag with background, shadow, and rounded corners.
Position offset so the pointer tip is at the actual lat/lng.
### D4: Join/leave toasts
When awareness detects a new client or a client leaving, show a brief toast
("Alice joined" / "Bob left") that auto-dismisses after 3 seconds. Use a
simple absolute-positioned div, no toast library.

View file

@ -0,0 +1,35 @@
## Why
The Planner supports collaborative editing but the multiplayer experience is
bare. Users can't see who else is in the session. Cursor labels are small
floating divs that look broken (no proper styling, overlap with map controls).
Users get randomly assigned names like "Hiker" or "Explorer" with no way to
change them. This makes collaboration confusing — you can't tell who is who.
## What Changes
- **Participant list**: Show who's in the session (name, color, host badge)
in the sidebar or header
- **Name editing**: Let users set their name after joining (persisted in
localStorage, synced via Yjs awareness)
- **Cursor styling**: Fix cursor labels — proper pointer icon, name tag with
shadow, avoid overlap with map controls
- **Connection indicators**: Show when participants join/leave
## Capabilities
### New Capabilities
(None — this enhances existing Yjs awareness features.)
### Modified Capabilities
- `planner-session`: Session view gains participant list and name editing
- `map-display`: Map cursor rendering improved
## Impact
- **Files**: `PlannerMap.tsx` (cursor styling), `SessionView.tsx` (participant
list), `use-yjs.ts` (name editing), new `ParticipantList` component
- **Dependencies**: None
- **i18n**: New keys for participant labels and name editing

View file

@ -0,0 +1,12 @@
## MODIFIED Requirements
### Requirement: Map cursor rendering
Other participants' cursors on the map SHALL be clearly visible with proper styling.
#### Scenario: Cursor appearance
- **WHEN** another participant moves their mouse on the map
- **THEN** a colored pointer icon with their name tag appears at the cursor position
#### Scenario: Cursor does not obscure map controls
- **WHEN** cursors are rendered
- **THEN** they appear below map controls (zoom, layer switcher) in z-index

View file

@ -0,0 +1,28 @@
## MODIFIED Requirements
### Requirement: Session participant awareness
Users in a planning session SHALL see who else is present and be able to identify themselves.
#### Scenario: Participant list visible
- **WHEN** multiple users are in a session
- **THEN** the header shows each participant's name and color
#### Scenario: Host badge
- **WHEN** a participant is the routing host
- **THEN** their entry in the participant list shows a host indicator
#### Scenario: Edit own name
- **WHEN** a user clicks their own name in the participant list
- **THEN** an inline text input appears to change their display name
#### Scenario: Name persisted
- **WHEN** a user changes their name
- **THEN** the name is saved to localStorage and immediately visible to all other participants via awareness
#### Scenario: Join notification
- **WHEN** a new participant joins the session
- **THEN** a brief toast shows "[name] joined"
#### Scenario: Leave notification
- **WHEN** a participant leaves the session
- **THEN** a brief toast shows "[name] left"

View file

@ -0,0 +1,27 @@
## 1. Name Editing
- [x] 1.1 Update use-yjs.ts: allow updating user name via a returned setter function
- [x] 1.2 Save updated name to localStorage and sync via awareness.setLocalStateField
- [x] 1.3 Add i18n keys for participant UI (en + de)
## 2. Participant List
- [x] 2.1 Create ParticipantList component showing all awareness states (name, color dot, host badge)
- [x] 2.2 Add inline name edit when clicking own name in the list
- [x] 2.3 Integrate ParticipantList into SessionView header
## 3. Cursor Styling
- [x] 3.1 Replace current divIcon cursor with SVG pointer arrow + styled name tag (background, shadow, rounded)
- [x] 3.2 Set cursor z-index below map controls to avoid overlap
## 4. Join/Leave Toasts
- [x] 4.1 Track awareness changes (added/removed clients) in SessionView
- [x] 4.2 Show auto-dismissing toast when participant joins or leaves (3 second duration)
## 5. Verify
- [x] 5.1 Test with two browser windows: verify participant list, name editing, cursor rendering
- [x] 5.2 Verify join/leave toasts appear correctly
- [x] 5.3 Verify name persists across page refresh (localStorage)