BACK_TO_BLOG
·3 min read·Building / Engineering

Switchback, not Kickstand: a name change and a full v1 scaffold

Rebranded the moto app after finding a name collision, then built out the public site, POI system, and SMC trading indicator.

The product I've been calling Kickstand isn't Kickstand anymore. There's an existing iOS app in the Navigation category by that name, so the whole thing is now Switchback (switchback-moto.com). One commit swept every user-facing reference — metadata, emails, blog content, tests, docs — while leaving the kickstand-web repo directory alone. Renaming the repo is a separate problem for a separate day.

That was one commit out of fifty-nine on kickstand-web this week. Most of the others were the v1 web scaffold going from empty to actually-a-site.

The web app, end to end

Starting from create-next-app and ending at something deployable:

  • Database first. Init migration for pois, waitlist, blog_posts, plus RLS policies and an is_admin() helper. Generated TypeScript types off the schema. Added a nearby_pois PostGIS RPC and a poi-images Storage bucket.
  • Public surface. Landing, pricing, download, about, legal (with real privacy/terms/cookies copy and an attorney-review disclaimer), 404, error boundary.
  • Waitlist. /api/waitlist with validation, an in-memory sliding-window IP rate limiter, Supabase upsert, and a Resend confirmation email. Playwright E2E covers the happy path.
  • Blog. MDX frontmatter parser, posts loader with draft filtering, index/detail/tag pages, custom MDX components.
  • SEO + observability. sitemap.xml, robots.txt (blocks non-prod, blocks /admin and /api on prod), RSS feed, Vercel Analytics + Speed Insights, Sentry wired up and verified with a temporary /api/sentry-test endpoint that's already been removed.
  • POI system. This was the bigger piece. A YAML seed importer (scripts/seed-pois.ts) that idempotently upserts by slug, uploads hero images to Storage, and writes EWKT SRID=4326;POINT(lng lat) geography values for PostGIS. Detail pages with schema.org structured data and a nearby-POIs panel powered by the RPC. Category and region index pages. Six starter POIs with CC0 Unsplash hero images.

CI runs lint, typecheck, format check, unit tests, and Playwright on every PR. The Tailwind v4 migration cost me one bug — arbitrary CSS var values need to be wrapped in var() now, which the v3 syntax silently lets you skip.

Trading: parity with the legacy engine

Ten commits on the Trading repo, almost all on Pine. The main piece is smc-edge-sol.pine — a new SOL-specific manual-trading indicator that mirrors the legacy default SMC engine's multi-confluence scoring. The backtest the Pine logic is now matching: PF 1.43, 65.7% WR, 2225 trades, Sharpe 4.43 on SOLUSD H1 over five years. Original smc-trading-indicator.pine left alone.

Two bugs worth naming. First, the Pine version was firing 14 signals in four days on a window where the backtest fires roughly one a day. The engine enforces maxOpenPositions=1 but Pine wasn't gating new entries on the active-trade flag — so every cooldown window inside the same open trade re-fired. Fixed by feeding _hasOpenTrade back into the signal-fire condition. Second, that fix introduced a different failure: in ranging markets neither SL nor TP2 hits, so the active-trade state never clears and the entire rest of the chart goes silent. Added i_maxHoldBars (default 60 = 2.5 days on H1) to force-close the virtual position, matching the engine's implicit timeout.

Also split the visualization toggles. The entry/SL/TP lines and the LONG/SHORT position-size label used to share one input; they're now independent, with arrows + bar coloring + position label on by default and the per-signal lines off.

Next

Switchback admin CRUD for POIs is the next block of work — Plan 2 is already written. The TwofoldTech products didn't get touched this week. They will.