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
20 changes: 19 additions & 1 deletion BACKLOG.md
Original file line numberDiff line numberDiff line change
Expand Up@@ -24,7 +24,9 @@ Size: S (<1h) · M (1–3h) · L (3h+) · Model hint: `haiku` for S mechanical,
## 🚀 MVP release punch-list (2026-09-01 — owner mobile testing)
Filed from live mobile testing of `odyssey-trips.vercel.app`. Owner flagged all as
**essential for MVP release.** Priority order for the release: **ODY-121 → ODY-120 →
ODY-124 → ODY-122 → ODY-123** (ODY-123 is research/decision, so it gates itself).
ODY-124 → ODY-122 → ODY-125 → ODY-126 → ODY-123** (ODY-123 is research/decision, so
it gates itself; ODY-126 folds packing/event-linking scope into ODY-067 Stage B if
that's picked up separately).

### ODY-120 · New-trip wizard: "Add member" is easy to miss on mobile — S, sonnet (P1) — 🔴 MVP
> **In plain terms:** On the create-a-trip form you type a collaborator's email, but on mobile it's not obvious you then have to tap a separate "Add" button — so people finish the wizard thinking they invited someone, then find the members list empty and have to re-add them.
Expand DownExpand Up@@ -57,6 +59,22 @@ ODY-124 → ODY-122 → ODY-123** (ODY-123 is research/decision, so it gates its
- **Fix:** replace the redundant weekday heading with the day's **location**. Deriving the location: the trip `destination` (single-city trips) or, for multi-city, infer per-day from that day's events' `location`/city (first event with a city), falling back to the trip destination. Keep the date line as-is. Consider a small `deriveDayLocation(day, trip)` helper (pure, unit-testable). Editorial styling unchanged (serif display heading, just different text).
- **Acceptance:** each day header reads "DAY NN · <City>"; the weekday is no longer duplicated; a multi-destination trip shows different cities on different days; a single-destination trip shows the trip city.

### ODY-125 · Dashboard: "N travelers" stat double-counts repeat collaborators and wraps ugly — S, haiku (P2) — 🔴 MVP
> **In plain terms:** The dashboard's "travelers" stat counts a member once per trip they're on, so a person who collaborates on 3 trips gets counted 3 times — the number doesn't mean anything real. It also line-wraps awkwardly next to "adventures" and "days planned" on mobile.
- **Repro (owner, screenshot):** dashboard stats row shows "9 adventures · 41 days planned · 31 travelers" — 31 is a sum of per-trip member counts, not distinct people, and the third stat drops to its own line at 375px instead of staying inline or wrapping cleanly.
- **Fix:** compute the travelers stat as the count of **distinct users** across all of the owner's trips (dedupe by user id, e.g. via `TripMember` grouped/distinct query in the dashboard's data-loading action), not a per-trip sum. Pair with a mobile layout fix for the stats row — either allow it to wrap as a proper multi-line flex/grid with consistent gaps, or keep it on one line with a smaller/responsive type size at narrow widths — whichever keeps the editorial stat row from breaking mid-number.
- **Files:** dashboard data query (wherever the trips-overview stats are aggregated, e.g. `app/(dashboard)` or `app/page.tsx` server action / `lib/prisma`), stats row component + its CSS in `globals.css`.
- **Acceptance:** a user who collaborates with the same 5 people across multiple trips sees "5 travelers," not an inflated per-trip sum; at 375px the stats row reads cleanly with no orphaned single stat on its own line.

### ODY-126 · Trip notes sections: default-collapse noise, add-section toast, and move Packing List to its own mappable tab — M, sonnet (P2) — 🔴 MVP
> **In plain terms:** The itinerary page currently opens with "Important Reminders," "Packing List," and "To Do" all expanded, pushing the actual day-by-day plan below the fold — travelers have to scroll past empty boilerplate to get to planning. This collapses that noise by default, tells people what else they can add there, and moves packing into its own tab where it can eventually link an item to a specific event (e.g. hiking boots → the hiking day).
- **Repro (owner, screenshots):** itinerary page opens showing all three note sections (Reminders/Packing/To Do) expanded with "Add items…" placeholders before any itinerary content is visible.
- **Fix, three parts:**
1. **Default-collapse:** in `TripNotes.tsx`/`NoteSection.tsx` (ODY-104/105), only **Important Reminders** defaults to open; **Packing List** and **To Do** (and any other non-default section) default to **collapsed** on first render. Respect the user's own toggle thereafter (don't fight an explicit expand).
2. **Discoverability toast:** when a trip's notes have no custom sections yet (or on first visit to the itinerary page), show a one-time toast (reuse `src/components/shared/Toast`, ODY-013 pattern) suggesting example sections a user can add via "Add section" (e.g. "Packing List," "To Do," "Emergency Contacts"). Don't nag — dismiss persists per-trip the same way ODY-085's welcome dismissal does (cookie/db flag, **not localStorage** per project rules).
3. **Move Packing List off the itinerary page:** remove the Packing List section from the itinerary's notes area entirely; its own tab (already liked by the owner) becomes the single home for packing. In that tab, extend the packing item model so an item can optionally be linked to one or more specific events/days (e.g. a join table or an `eventIds`/`dayId` field on the packing item) so "hiking boots" can be tied to the hiking-trail event or a specific day/time. Filed as the follow-up ODY-067 Stage B in this backlog already covers per-event packing — **this ticket's linking scope should fold into that Stage B work rather than duplicate it**; if ODY-067 Stage B is picked up separately, split part 3 out and only ship parts 1–2 here.
- **Acceptance:** itinerary page loads with only Important Reminders expanded (Packing/To Do collapsed) and no Packing List section present at all; a first-time-per-trip toast names example sections; the Packing tab is the only place packing lives, with a path (even if Stage B ships later) to associate an item with a specific event/day.

---

## P0 — Correctness & Security
Expand Down
178 changes: 178 additions & 0 deletions docs/mvp-roadmap-2026-09-02.md
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,178 @@
# Odyssey — MVP Roadmap Planning Doc (2026-09-02)

> **Status: PLANNING ONLY.** Nothing here is committed to `BACKLOG.md` yet. This
> is a highlight-level map of the six workstreams the owner raised in one sitting,
> grounded against current git history (`main` @ `2c62ef8`, verified 2026-09-02),
> so we can sequence and scope before turning any of it into tickets. Once a
> workstream is agreed, split it into properly-scoped `ODY-###` tickets in
> `BACKLOG.md` following the existing format (In plain terms → repro/files →
> acceptance).

---

## Why this order

Two things gate everything else and should move first:

1. **Clerk production domain** (ODY-036) — until real auth exists, invite links,
real user identities, and any "who's on this trip" feature are all built on
a placeholder. This is the single biggest launch blocker already logged.
2. **A safe checkpoint before the design refresh** — fonts + spacing changes
touch nearly every screen. We want a clean, tagged commit to hand to Claude
Design and a clean branch to hand back to Claude Code, so a visual pass
doesn't get tangled with in-flight feature branches.

Everything else (mobile audit, Explore provider swap, globe recolor, doc
cross-check) can run in parallel once those two are moving.

---

## 1. Clerk production auth + real invite links (launch blocker)

**Already scoped in the backlog** as ODY-036 (prod Clerk + Google OAuth) and
ODY-037 (real invitations/join flow/guest access) — ODY-037 explicitly depends
on ODY-036. Nothing new to invent here; this is a sequencing decision, not a
research task.

- **ODY-036** — point the app at a production Clerk instance (not the dev
"practice mode" instance), wire up Google OAuth for prod.
- **ODY-037** — once prod auth exists, invite emails need to carry a **real
domain link** (not a placeholder/dev URL) that lands the invitee on the join
flow for that specific trip.
- **Cross-cutting ask from this session:** audit `BACKLOG.md` itself once
ODY-036/037 ship — confirm every ticket in the doc that assumed "prod auth
not stable yet" (there are several: ODY-045 follow-ons, ODY-068 offline,
ODY-112 receipt capture gating) gets its gate lifted or explicitly re-gated,
rather than silently going stale. This is a documentation-hygiene pass, not
new code — same spirit as the "ground truth is git, not the doc" rule already
in the backlog's header.

**Owner action needed:** the actual domain (what real domain the invite link
points to) and DNS/Clerk dashboard access are outside what a coding session can
decide — needs the domain name + Clerk production keys before ODY-036 can be
implemented, not just planned.

---

## 2. Design refresh — typography, spacing, safe checkpoint for Claude Design handoff

Three distinct pieces, sequenced so nothing gets designed against code that's
about to move:

1. **Cut a safe checkpoint.** Before any visual work starts: confirm `main` is
green (tests/build/lint), tag or branch it (e.g.
`checkpoint/pre-design-refresh-2026-09`), and hand that exact commit to
Claude Design. This makes "handoff back to Claude Code" unambiguous — Claude
Code resumes from the tagged commit, not from whatever `main` has drifted to.
2. **New font pairing, less "AI-generated" look.** Current stack is DM Serif
Display / DM Sans / JetBrains Mono — these are legitimate, purposeful
choices already but read as a common "safe AI pick" pairing. Needs a
**design research pass** (Claude Design, using the `design`/`design-mockup`
skill) to propose 2–3 alternate serif+sans pairings that keep the
"boarding pass + printed map" editorial feel — same personality, different
typefaces — plus a mockup to approve before wiring into
`next/font/google` and the `globals.css` `@theme` tokens.
3. **Desktop white-space audit.** Independent of fonts — likely a layout/
container-width issue (max-width too narrow relative to viewport, or
vertical rhythm too generous) rather than a token problem. Needs a screen-
by-screen desktop pass (dashboard, itinerary, map, budget, schedule) to
find where the editorial "breathing room" tips into "empty."

**Sequencing:** checkpoint tag → Claude Design mockup (fonts + fixes for the
worst white-space offenders) → owner approval → Claude Code implements against
the tagged checkpoint, not against whatever else has merged to `main` since.

---

## 3. Mobile UI audit — seamless user journey

This is broader than the ODY-120–126 mobile fixes already filed (add-member
visibility, date-picker spacing, Explore action buttons, traveler stat wrap,
notes-section collapse). Those are **point fixes** found from one round of
owner testing. What's being asked for now is a **structured, full-journey
audit**: sign-up → create trip → invite → build itinerary → explore → schedule
→ budget → settle-up, walked end-to-end on a real phone (or Playwright at
375–428px), looking for friction rather than isolated bugs.

- Reuse the existing pattern from ODY-046 ("full user-journey QA audit") and
ODY-108 (full UI/UX design audit) — same audit discipline, mobile-scoped.
ODY-046 is already listed as open in the backlog; this may simply be that
ticket, executed now.
- Deliverable: a findings doc (like `docs/ody-108-design-audit.md` /
`docs/ody-118-accessibility-audit.md`) ranking friction points, which then
get filed as individual tickets — not one giant ticket.

---

## 4. Explore provider research — Google Places swap

**Research + decision, not a build yet** — this direction already exists in
the backlog as **ODY-123** (research+decision ticket for richer Explore
preview: map thumbnail, photos, reviews, "open in Google Maps"), filed
specifically because it was flagged as "decide before build." What's new in
this ask:

- **Reviews** — Google Places has them; current provider (Foursquare, chosen
for its free tier per ODY-119's notes) doesn't expose review content the
same way.
- **Map view with distance/info** — an in-card or in-panel map preview,
distance from other itinerary stops, richer place info.
- **Multi-city support** — partially exists already: `splitDestinations`
(`src/lib/destinations.ts`, shipped 2026-09-01) parses multi-city trip
destinations and Explore filters by city chip. What's *not* yet covered:
whether a Google Places swap changes how multi-city search/ranking works,
and whether itinerary-side multi-city display (ODY-124, city-per-day
headers) needs to know about the same city list.

**This should extend ODY-123's existing research memo**, not start a second
one — add a Google Places section (cost per call, review data availability,
attribution/ToS requirements, quota) alongside the "zero-provider-switch"
option (static map + deep-link) it already proposed. The owner explicitly
flagged this earlier as a cost tradeoff to decide, not rubber-stamp — that
constraint still holds.

---

## 5. Three.js globe — recolor to purple gradient

Small, isolated, cosmetic. `Globe3D` (landing page) already exists and already
has a reduced-motion accessibility fix (ODY-118 F4, ships idle-spin stillness
for `prefers-reduced-motion`). This is a shader/material color-parameter
change — swap whatever current gradient/color uniforms it uses for a purple
gradient consistent with the `--peri` token family, not a new component. Low
risk, easy to slot in alongside the design refresh (workstream 2) since it's
touching the same "brand look" surface — worth doing in the same pass rather
than as a separate thread.

---

## 6. Mobile app development checklist — cross-check against current plans

The owner has a Google Doc checklist for mobile app development that needs to
be diffed against what's already in `BACKLOG.md`'s mobile-related tickets
(ODY-058/059 mobile chrome, ODY-096 mobile overflow, ODY-102/103 notes mobile
fixes, the new ODY-120–126 punch list, and the "Post-MVP: ODY-073 native"
line already in the backlog's priority list).

**Blocked on access** — I don't have a way to read a Google Doc from here.
**Owner action needed:** either paste the checklist content in, share it as an
exported file, or grant a way to fetch it, and the next session can do the
gap analysis (what's covered, what's missing, what's redundant) in one pass.

---

## Suggested sequencing (once this doc is reviewed)

| Order | Workstream | Depends on | Can run in parallel with |
|---|---|---|---|
| 1 | Clerk prod domain (ODY-036) | owner's domain + Clerk prod keys | 3, 4, 5, 6 |
| 2 | Real invite links + backlog audit (ODY-037 + doc hygiene) | (1) | 3, 4, 5, 6 |
| 3 | Mobile UI audit (full journey) | none | 1, 2, 4, 5, 6 |
| 4 | Explore/Google Places research (extends ODY-123) | none | 1, 2, 3, 5, 6 |
| 5 | Design checkpoint → fonts + spacing + globe recolor | a tagged checkpoint commit | 1, 2, 3, 4 |
| 6 | Google Doc checklist gap analysis | owner shares the doc | everything |

Nothing above is committed to `BACKLOG.md`. Next step is the owner picking
which of these become real tickets first (or confirming this order), then a
session turns each into properly-scoped `ODY-###` entries the same way
ODY-120–126 were filed.
Loading