Decisions
Marketing at the root, SaaS at /app
signaldock.dev serves the marketing site; the product is mounted at signaldock.dev/app.
Status: accepted · 2026-09-25
Context
SignalDock ships as one Vercel project with Vercel Services: app, api,
mcp and docs, routed by path rewrites in the root vercel.json. Until
now the SaaS app answered every path that no other service claimed, so the
product owned /.
We need a public site (home, pricing, compare, customer stories, changelog, blog) that is fast, indexable and independent of the authenticated app.
Decision
- Add a
marketingservice (apps/marketing, Next.js) that serves/and every path not claimed by another service. - Mount the SaaS app at
/app. The/appand/app/(.*)rewrites route to theappservice ahead of the marketing catch-all. The platform keeps the public path, so the SaaS app sets NextbasePath: "/app": pages, links,redirect()and/_nextassets are all prefixed once. /api,/mcp,/.well-known/oauth-protected-resourceand/docskeep their rewrites. Everything is one origin, so the app calls the API same-origin and needs no CORS.- Marketing and docs stay separate apps. Marketing links to the docs and the app with absolute URLs and never proxies them.
- The SaaS URL is configuration:
NEXT_PUBLIC_SITE_URLishttps://www.signaldock.dev/appin production, and Supabase Authsite_urland redirect URLs include/app, so OAuth consent lands on/app/oauth/consent. - Env vars are shared by every service in a Vercel project, so marketing does
not read
NEXT_PUBLIC_SITE_URL. It derives its origin fromVERCEL_PROJECT_PRODUCTION_URL(production) orVERCEL_URL(preview), so preview deployments link to their own/appand/docs.
This is a breaking change with no redirects. The product is greenfield, so there are no existing links to preserve.
Consequences
- Marketing depends only on
ui,domainandconfig(turbo boundary tagmarketing). The live score explorer runs the real@signaldock/domain/scoringengine in the browser, with no API call. NextResponse.redirecttakes an absolute URL and does not addbasePath; route handlers build redirect targets withappUrl()fromapps/app/lib/base-path.ts.- Locally Portless serves marketing on
https://www.localhostand the app onhttps://app.localhost/app(/redirects there).
Last updated on