Application case study · Cycling route planner
SikadNow PH
Planning the ride before the first pedal stroke.
A cycling route planner for riders in the Philippines. I built ordered route editing, cycling directions, terrain exploration, and private route storage, with a map-first workspace that connects the route to its elevation profile.
- My role
- Solo full-stack developer
- Stage
- In-development MVP
- Intended audience
- Cyclists planning rides in the Philippines
- Scope
- Route editing, provider integration, terrain, persistence, and rider profiles

On this page
Project status and evidence
Feature status is based on the supplied project documentation and its account of repository implementation. This portfolio review did not independently audit the application repository or production behavior. Effort analysis and AI coaching remain planned; no adoption or fitness outcomes are claimed.
Understand the route before riding it.
I built SikadNow PH as a solo full-stack project to help cyclists in the Philippines understand a route before riding it. The current implementation combines ordered stops, cycling-specific directions, terrain visualization, private route storage, and rider-profile management.
The longer-term product adds deterministic effort estimates and AI-written coaching. Those features remain planned: calculations will establish the numbers, while AI will explain them. The current project is an in-development MVP, not a completed integrated analysis product.
A ride is more than a start and finish.
A cycling plan can include a meeting point, water stops, climbs, and a finish location. A line between two points does not explain how those stops connect or what the terrain looks like. SikadNow's documented motivation is to bring cycling-specific routing and terrain information into one private planning workspace.
This is product framing rather than a formal comparison of mapping providers or a validated research persona. The application is a pre-ride planner: live GPS tracking, recorded ride activity, social feeds, native mobile apps, offline maps, and group planning are outside the current MVP.
- Make stop order explicit
- Let riders add, label, reposition, remove, and reorder the locations that define the ride.
- Connect terrain to place
- Show elevation and gradient information alongside the route, with controls that connect a chart point to a location on the map.
- Keep future estimates transparent
- Effort analysis needs an explicit rider target and clearly labeled assumptions. A route alone cannot determine how hard someone will ride.
One shared model, two editing experiences.
I owned the full-stack implementation, including page and component structure, route-editing interactions, routing-provider integration, persistence, authorization, rider profiles, and supporting tests. I separated the editable route from its calculated geometry and terrain so changed inputs and stale results could be handled explicitly.
The saved-route redesign makes the map the main workspace. A floating panel keeps route identity, save state, directions, and stops close to the route they affect. Desktop uses a utility rail; mobile uses a bottom sheet to preserve map context.
The new-route page retains its document-style editor. Both layouts share the editor controller rather than duplicating validation, save, and conflict behavior. The product's green and warm-yellow accents remain distinct from the portfolio's visual system.

Build, inspect, and return to the plan.
The current journey starts with Google sign-in and a private route collection. The rider names a route, adds and refines ordered stops, saves the draft, and then requests cycling directions in the saved-route workspace. They can inspect distance, elevation gain and loss, and gradients before returning to edit the plan.
Terrain charts and the map share a route cursor. Point selection, a range slider, and play/pause controls support exploration without relying solely on hover. Playback moves through terrain samples; its animation duration is not a modeled ride time.
Route history lists saved plans, not recorded rides. Loading states, field errors, save feedback, conflict recovery, and unsaved-change protection keep the next action visible when something goes wrong.
- Build an ordered route
- Place and label stops, move markers, and use move-up or move-down controls to define the intended route order.
- Inspect cycling terrain
- Choose a cycling profile, calculate directions, and explore synchronized elevation and gradient information.
- Reopen and revise
- Return to privately saved routes, resolve stale-edit conflicts, save changes, or delete a plan after confirmation.

A calculation must belong to the current route.
Mapbox GL JS provides the interactive basemap; OpenRouteService supplies cycling directions and elevation; Recharts visualizes terrain. Next.js and React connect the interface to authenticated services, Auth.js manages Google sign-in, and Prisma with PostgreSQL persists owned routes, pins, profiles, and derived calculations. TypeScript and Zod define and validate the boundaries.
The architecture distinguishes editable input from derived output. Numeric analysis and future AI prose have separate records so narrative regeneration cannot overwrite calculations. Provider failures are surfaced as actionable states rather than substituted route or elevation data.
- Stop order is domain data
- Application validation checks contiguous order, reads sort explicitly, and database constraints protect uniqueness. Route and pin changes use transactions.
- Conflicts are recoverable
- Updates include an expected timestamp. Newer stored edits produce a conflict instead of a silent overwrite, while changed pins invalidate derived calculations transactionally.
- Cache identity is correctness
- Input hashes, routing profiles, and calculation versions govern reuse. A result is rejected if the route changes while the provider request is running.
- Terrain normalization is explicit
- Duplicate-distance samples are combined, interior elevation samples are smoothed, and gradients require a minimum baseline. These rules make processing testable, not a guarantee of real-world terrain accuracy.
Make assumptions and ownership visible.
Routes and rider profiles are private. Reads and mutations derive ownership from the active session rather than accepting a client-supplied owner identifier. Runtime schemas validate external input, and server-only provider and database credentials remain outside client modules.
Profiles store weight, experience, bike type, and optional FTP. Measured, user-entered, estimated, and unknown FTP remain distinct states. An optional coarse estimate requires confirmation and source attribution; it is not a substitute for an FTP test, and unknown FTP does not block route planning.
The planned effort layer requires a power, speed, or duration target. Deterministic, versioned calculations will establish estimates; the planned AI layer will explain them without revising numeric results. Cycling-profile output is not a guarantee of road safety or surface suitability.
A working foundation, with the roadmap in view.
The supplied documentation describes repository implementations and tests for route editing, persistence, directions, terrain, profiles, and supporting boundaries. Those are implementation outcomes, not evidence of planning-time savings, improved fitness, production use, or user satisfaction.
Verification covers pin-order rules, terrain normalization, cache identity, ownership, conflict recovery, and interface behavior. Some browser tests use fixture directions, so they demonstrate UI integration rather than live routing-provider behavior. Database and provider-dependent checks require their configured environments.
- Implemented in the repository
- Google authentication, ordered route editing, private persistence, cycling directions, terrain visualization, rider profiles, and supporting tests.
- Incomplete or pending verification
- Verified email/password authentication and rider-facing account recovery are incomplete. Complete live-provider, database, accessibility, and device acceptance still need recorded evidence.
- Planned analysis
- Modeled effort, ride time, calories, FTP zones, and Anthropic coaching are not yet an integrated feature. They remain separate from the current route-planning foundation.
Trust comes from the relationship between input and output.
The project showed me that a trustworthy route planner depends on the relationship between user input and derived data. A fast calculation is only useful when it still belongs to the current route. Shared map and chart context, explicit ordering, and recoverable conflicts make that relationship understandable.
The next steps are completing authentication, implementing deterministic effort analysis, and validating the integrated planning experience before adding narrative coaching. Observing riders complete the workflow would provide evidence about where they hesitate or misunderstand terrain; that validation has not yet been claimed.
Technologies used
- Next.js
- React
- TypeScript
- Tailwind CSS
- shadcn/ui
- Auth.js
- Prisma
- PostgreSQL
- Mapbox GL JS
- OpenRouteService
- Recharts
- Zod