From c7c1c275df40a2a6a6e4a28dd168ea675f75c601 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ullrich=20Sch=C3=A4fer?= Date: Wed, 25 Mar 2026 03:57:20 +0100 Subject: [PATCH] Add 8 proposed changes and old trails analysis MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 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) --- docs/old-trails-analysis.md | 235 ++++++++++++++++++ .../changes/app-navigation/.openspec.yaml | 2 + openspec/changes/app-navigation/design.md | 40 +++ openspec/changes/app-navigation/proposal.md | 33 +++ .../app-navigation/specs/map-display/spec.md | 12 + openspec/changes/app-navigation/tasks.md | 18 ++ openspec/changes/changelog/.openspec.yaml | 2 + openspec/changes/changelog/design.md | 65 +++++ openspec/changes/changelog/proposal.md | 38 +++ .../changes/changelog/specs/changelog/spec.md | 37 +++ openspec/changes/changelog/tasks.md | 29 +++ openspec/changes/komoot-import/.openspec.yaml | 2 + openspec/changes/komoot-import/design.md | 72 ++++++ openspec/changes/komoot-import/proposal.md | 32 +++ .../komoot-import/specs/komoot-import/spec.md | 63 +++++ .../specs/route-management/spec.md | 12 + openspec/changes/komoot-import/tasks.md | 51 ++++ .../changes/planner-features/.openspec.yaml | 2 + openspec/changes/planner-features/design.md | 74 ++++++ openspec/changes/planner-features/proposal.md | 40 +++ .../specs/brouter-integration/spec.md | 8 + .../specs/crash-recovery/spec.md | 12 + .../specs/map-display/spec.md | 12 + .../specs/no-go-areas/spec.md | 16 ++ .../specs/planner-session/spec.md | 8 + .../specs/rate-limiting/spec.md | 15 ++ .../specs/session-notes/spec.md | 12 + openspec/changes/planner-features/tasks.md | 36 +++ .../planner-landing-page/.openspec.yaml | 2 + .../changes/planner-landing-page/design.md | 44 ++++ .../changes/planner-landing-page/proposal.md | 34 +++ .../specs/planner-session/spec.md | 16 ++ .../changes/planner-landing-page/tasks.md | 16 ++ .../.openspec.yaml | 2 + .../planner-multiplayer-awareness/design.md | 46 ++++ .../planner-multiplayer-awareness/proposal.md | 35 +++ .../specs/map-display/spec.md | 12 + .../specs/planner-session/spec.md | 28 +++ .../planner-multiplayer-awareness/tasks.md | 27 ++ .../changes/route-features/.openspec.yaml | 2 + openspec/changes/route-features/design.md | 71 ++++++ openspec/changes/route-features/proposal.md | 43 ++++ .../specs/activity-feed/spec.md | 12 + .../specs/activity-photos/spec.md | 16 ++ .../specs/multi-day-routes/spec.md | 16 ++ .../specs/route-management/spec.md | 12 + .../specs/route-sharing/spec.md | 30 +++ .../specs/spatial-search/spec.md | 12 + openspec/changes/route-features/tasks.md | 68 +++++ .../transactional-emails/.openspec.yaml | 2 + .../changes/transactional-emails/design.md | 62 +++++ .../changes/transactional-emails/proposal.md | 32 +++ .../specs/journal-auth/spec.md | 12 + .../specs/transactional-emails/spec.md | 44 ++++ .../changes/transactional-emails/tasks.md | 30 +++ 55 files changed, 1704 insertions(+) create mode 100644 docs/old-trails-analysis.md create mode 100644 openspec/changes/app-navigation/.openspec.yaml create mode 100644 openspec/changes/app-navigation/design.md create mode 100644 openspec/changes/app-navigation/proposal.md create mode 100644 openspec/changes/app-navigation/specs/map-display/spec.md create mode 100644 openspec/changes/app-navigation/tasks.md create mode 100644 openspec/changes/changelog/.openspec.yaml create mode 100644 openspec/changes/changelog/design.md create mode 100644 openspec/changes/changelog/proposal.md create mode 100644 openspec/changes/changelog/specs/changelog/spec.md create mode 100644 openspec/changes/changelog/tasks.md create mode 100644 openspec/changes/komoot-import/.openspec.yaml create mode 100644 openspec/changes/komoot-import/design.md create mode 100644 openspec/changes/komoot-import/proposal.md create mode 100644 openspec/changes/komoot-import/specs/komoot-import/spec.md create mode 100644 openspec/changes/komoot-import/specs/route-management/spec.md create mode 100644 openspec/changes/komoot-import/tasks.md create mode 100644 openspec/changes/planner-features/.openspec.yaml create mode 100644 openspec/changes/planner-features/design.md create mode 100644 openspec/changes/planner-features/proposal.md create mode 100644 openspec/changes/planner-features/specs/brouter-integration/spec.md create mode 100644 openspec/changes/planner-features/specs/crash-recovery/spec.md create mode 100644 openspec/changes/planner-features/specs/map-display/spec.md create mode 100644 openspec/changes/planner-features/specs/no-go-areas/spec.md create mode 100644 openspec/changes/planner-features/specs/planner-session/spec.md create mode 100644 openspec/changes/planner-features/specs/rate-limiting/spec.md create mode 100644 openspec/changes/planner-features/specs/session-notes/spec.md create mode 100644 openspec/changes/planner-features/tasks.md create mode 100644 openspec/changes/planner-landing-page/.openspec.yaml create mode 100644 openspec/changes/planner-landing-page/design.md create mode 100644 openspec/changes/planner-landing-page/proposal.md create mode 100644 openspec/changes/planner-landing-page/specs/planner-session/spec.md create mode 100644 openspec/changes/planner-landing-page/tasks.md create mode 100644 openspec/changes/planner-multiplayer-awareness/.openspec.yaml create mode 100644 openspec/changes/planner-multiplayer-awareness/design.md create mode 100644 openspec/changes/planner-multiplayer-awareness/proposal.md create mode 100644 openspec/changes/planner-multiplayer-awareness/specs/map-display/spec.md create mode 100644 openspec/changes/planner-multiplayer-awareness/specs/planner-session/spec.md create mode 100644 openspec/changes/planner-multiplayer-awareness/tasks.md create mode 100644 openspec/changes/route-features/.openspec.yaml create mode 100644 openspec/changes/route-features/design.md create mode 100644 openspec/changes/route-features/proposal.md create mode 100644 openspec/changes/route-features/specs/activity-feed/spec.md create mode 100644 openspec/changes/route-features/specs/activity-photos/spec.md create mode 100644 openspec/changes/route-features/specs/multi-day-routes/spec.md create mode 100644 openspec/changes/route-features/specs/route-management/spec.md create mode 100644 openspec/changes/route-features/specs/route-sharing/spec.md create mode 100644 openspec/changes/route-features/specs/spatial-search/spec.md create mode 100644 openspec/changes/route-features/tasks.md create mode 100644 openspec/changes/transactional-emails/.openspec.yaml create mode 100644 openspec/changes/transactional-emails/design.md create mode 100644 openspec/changes/transactional-emails/proposal.md create mode 100644 openspec/changes/transactional-emails/specs/journal-auth/spec.md create mode 100644 openspec/changes/transactional-emails/specs/transactional-emails/spec.md create mode 100644 openspec/changes/transactional-emails/tasks.md diff --git a/docs/old-trails-analysis.md b/docs/old-trails-analysis.md new file mode 100644 index 0000000..731861a --- /dev/null +++ b/docs/old-trails-analysis.md @@ -0,0 +1,235 @@ +# Feature Analysis: /Users/ullrich/Projects/trails + +Analysis of the older trails Remix app for features and patterns that could be +ported or adapted for trails-cool. Organized by category with implementation +references. + +## Social Features + +### Reactions/Kudos System +Allow users to react to activities with configurable reaction types (currently +"kudos"). Generic implementation supports any target type (profile, activity, +etc.). UI shows reaction counts on activity cards. + +- `drizzle/models/social-interactions.ts` +- `app/routes/api+/activities.$activityId.reactions.ts` + +### Comments/Replies +Thread-based comment system on activities. Comments stored as social +interactions with "reply" kind. Shows reply counts alongside reactions. + +- `app/routes/api+/activities.$activityId.replies.ts` +- `app/routes/feed.tsx` + +### User Following +Follow/unfollow user profiles with mutual follow tracking and uniqueness +constraints. Can be extended to follow specific routes or activities. + +- `app/routes/api+/follows.ts` +- `app/utils/social.server.ts` + +### Personalized Activity Feed +Feed showing activities from followed users, filtered by visibility (public, +followers-only, private). Shows interaction counts (reactions, replies). + +- `app/routes/feed.tsx` +- `app/utils/social.server.ts` + +## Import & Integration + +### Activity Import from External Services +Komoot integration for importing tours. Batch import tracking with status +(queued, running, completed, failed). Automatic deduplication using dedupeKey +prevents duplicate imports. Detailed statistics (totalFound, importedCount, +duplicateCount). + +- `app/inngest/importActivities.ts` +- `app/utils/integrations.server.ts` + +### Third-Party Sync Jobs +Background Inngest jobs for syncing external platforms. Handles credential +validation and error recovery. Tracks lastSyncedAt for incremental syncing. + +- `app/inngest/komootSync.ts` + +### Integration Connections Management +Store encrypted credentials for multiple service integrations. Track connection +status and last sync time. Support for multiple users connecting the same +integration independently. + +- `app/routes/integrations.tsx` +- `app/routes/api+/integrations.ts` + +## Route Planning + +### Ride Plan Scheduling +Schedule rides with timezone-aware start/end times. Privacy levels +(followers-only, private, public). Group ride flag for collaborative planning. + +- `drizzle/models/ride-plans.ts` + +### Route Geometry Encoding +Encoded polyline storage for efficient geometry. Route metrics: distance, +elevation gain, origin, destination. Multiple routes per ride plan. + +- `drizzle/models/ride-routes.ts` +- `app/components/ride-plans/route-editor.tsx` + +### Ride Plan Participants +Invite users to group rides. Track participation status (invited, accepted, +declined). Enables collaborative ride planning. + +- `drizzle/models/ride-plan-participants.ts` + +## Activity Tracking + +### Live Activity Recording +Start/pause/finish live recordings. Records start time, end time, duration, +distance, elevation gain. Manual form completion for recorded activities. +Activity status tracking (recording, paused, completed). + +- `app/components/activities/activity-recorder.tsx` +- `app/routes/api+/activities.recordings.start.ts` + +### Activity Visibility Levels +Public, followers-only, and private visibility options. Source tracking (native +recording vs. import). Link activities to specific ride plans and routes. + +- `drizzle/models/ride-activities.ts` + +## User Profile & Content + +### Profile Images +S3-compatible storage for profile pictures. Signed PUT requests for direct +client uploads. Image serving via openimg library for optimization. + +- `app/utils/storage.server.ts` +- `drizzle/models/user-images.ts` + +### User Notes/Blog +Rich note creation with title and markdown content. Image attachments to notes +(up to 5 images per note). Note listing and detail views. Image form validation +(3MB max per file). + +- `drizzle/models/notes.ts` +- `app/routes/users+/$username_+/notes.tsx` + +### Note Images +Upload and manage images within notes. Alt text support for accessibility. S3 +storage with organized paths. + +- `drizzle/models/note-images.ts` +- `app/routes/users+/$username_+/__note-editor.tsx` + +## Search & Discovery + +### User Search +Full-text search over username and display name. Pagination with limit of 50 +results. Search results with profile images. Case-insensitive matching. + +- `app/routes/users+/index.tsx` + +### Search Bar Component +Debounced auto-submit search. Reusable search UI component. Query parameter +preservation. + +- `app/components/search-bar.tsx` + +## Authentication & Settings + +### Two-Factor Authentication +TOTP-based 2FA on top of passkeys. Settings UI for enabling/disabling. +Verification flow. + +- `app/routes/settings+/profile.two-factor.tsx` + +### Email Verification +Email-based account verification. Verification token tracking. Email change +flow with verification. + +- `drizzle/models/verifications.ts` + +### Profile Management +Change email, password, name. Photo upload. Passkey management. Connected +OAuth providers (GitHub). + +- `app/routes/settings+/profile.tsx` + +## Federation + +### ActivityPub Foundation +Inbox/outbox endpoints for federated social network. Background publishing via +Inngest. Federation record tracking for local/federated entity mapping. + +- `app/routes/api+/activitypub.inbox.ts` +- `app/routes/api+/activitypub.outbox.ts` + +## Data Management + +### Activity Files Association +Attach files/media to activities. Track file metadata and relationships. + +- `drizzle/models/activity-files.ts` + +### Import Batch Tracking +Comprehensive import job tracking. Status lifecycle: queued, running, +completed, failed. Timing and statistics per batch. Progress monitoring in UI. + +- `drizzle/models/import-batches.ts` + +## Architectural Patterns + +### Role-Based Access Control +User roles and permission system. Basis for admin controls. Permission groups +for feature access. + +- `drizzle/models/roles.ts` +- `drizzle/models/permissions.ts` + +### Background Job Queue (Inngest) +Event-driven async processing. Reliable job retry with exponential backoff. +Step-based workflow for complex operations. Progress monitoring and error +handling. + +- `app/inngest/` + +### Deduplication Strategy +Unique composite keys (ownerId + dedupeKey) for imports. onConflictDoNothing +pattern prevents duplicates. Useful for imports from multiple sources. + +- `drizzle/models/ride-activities.ts` + +## UX/Component Patterns + +### Status Button +Button that displays async operation states (idle, pending, success, error). +Useful for form submissions and API calls. + +- `app/components/ui/status-button.tsx` + +### Form Validation (Conform + Zod) +Client/server validation with Conform.js and Zod. Constraint generation from +schemas. Field error display and form recovery. + +- `app/components/forms.tsx` + +## Priority Suggestions for trails-cool + +**High (directly applicable):** +- Reactions/Kudos — simple engagement, minimal schema +- Comments — essential social feature +- Following — core for Phase 2 federation +- Live Activity Recording — core outdoor feature +- User Search — discovery + +**Medium (enhances existing):** +- Profile images — user experience +- Activity visibility levels — privacy controls +- Import from Komoot/Strava — integration value +- Ride plan participants — collaborative planning + +**Lower (future):** +- Notes/Blog — content creation +- 2FA — security hardening +- Role-based access — admin features +- Background jobs (Inngest pattern) — already have infra for it diff --git a/openspec/changes/app-navigation/.openspec.yaml b/openspec/changes/app-navigation/.openspec.yaml new file mode 100644 index 0000000..40c5540 --- /dev/null +++ b/openspec/changes/app-navigation/.openspec.yaml @@ -0,0 +1,2 @@ +schema: spec-driven +created: 2026-03-25 diff --git a/openspec/changes/app-navigation/design.md b/openspec/changes/app-navigation/design.md new file mode 100644 index 0000000..c91ff69 --- /dev/null +++ b/openspec/changes/app-navigation/design.md @@ -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 `