Anchor issue — not urgent. Filed to capture intent + a grounded inventory so we can pick it up later without re-deriving it. General code organization / infra cleanup. The what/why/inventory below is the durable part; the how (candidate solutions) is expected to be stale by pickup time.
What
Split the www / marketing surface out of the editor Next.js app into its own independently-deployed project, while keeping everything on the single apex domain grida.co (no app.grida.co subdomain).
The editor app carries far more than its name implies — landing, the entire marketing site, the editor runtime, the workspace/dashboard, APIs, and multi-tenant site rendering all live in one build.
Current state (grounded — editor/app/)
Route groups today:
(api) (auth) (canvas) (demo) (dev) (embed) (ingest) (insiders)
(library) (preview) (site) (tenant) (theme) (tools) (untracked)
(workbench) (workspace) (www) + desktop/
The (www) group alone is a large public surface — each of these is a marketing/product page cluster:
(ai) (brand) (contact) (database) (dotcanvas) (downloads) (figma)
(forms) (home) (pricing) (printing) (sdk) (slides) (svg) (west) + kr (localized)
Meanwhile the product surfaces at root:
(workspace)/[org]/[proj]/... — the GitHub-style editor/workspace namespace
(site)/organizations/[organization_name]/settings/billing/... — authed org pages
(workbench) — the editor runtime
- host-based multi-tenant rendering —
{tenant}.grida.site / .grida.app, routed in editor/lib/tenant/middleware.ts via the app's proxy layer (isReservedAppHostname, platform-site canonicalization)
- global SEO —
editor/app/sitemap.ts at the app root
Why
- CI / build performance — a copy edit on
(www)/(pricing) currently rebuilds the entire editor (workbench, canvas, APIs). Split → two small, independent builds; marketing iterates without touching the editor pipeline. This is the primary motivation.
- Organization — a real ownership boundary between "the website" and "the product."
editor stops being a catch-all; (www)'s ~15 page clusters stop diluting the editor's build graph.
- Independent deploy / rollback — marketing and editor ship on their own cadence; a marketing deploy can't break the editor and vice-versa.
The constraint that makes this non-trivial
Both surfaces want root-level paths with no shared prefix: grida.co/ + grida.co/pricing + grida.co/svg (www) vs grida.co/{org}/{proj} (editor). This is not a clean /docs-style prefix split.
The resolution is forced:
- editor stays the default / fallback app —
{org}/{proj} is an unbounded catch-all, so it must be "everything not claimed."
- www owns a finite, enumerated set of root paths (
/, /pricing, /svg, /forms, /database, …).
⇒ the www path list is a reserved-slug list in the editor's [org] namespace (the GitHub reserved-username problem). Note we already carry this constraint inside the single app — grida.co/pricing and grida.co/{org} already can't both be free. The split doesn't add the constraint; it promotes the reserved list into an explicit routing table. Whichever solution we pick, that table becomes the source of truth and must stay in sync with the [org] slug validator.
Split boundary — starting classification (decide per-group at pickup)
| Group |
Lean |
Note |
(www) (+ kr) |
→ www |
the core of the split; the whole marketing surface |
(library) |
→ www? |
public, has its own sitemap.ts; could be www or its own zone |
(brand) / (downloads) / (contact) |
→ www |
already under (www) |
(site) |
stay editor |
authed org pages (settings/billing) |
(workspace) (workbench) (canvas) |
stay editor |
product runtime |
(api) (auth) (tenant) |
stay editor |
APIs, auth flow, host-based tenant rendering |
(tools) (preview) (embed) |
decide |
public-ish but coupled to the canvas runtime |
(insiders) (dev) (demo) (ingest) (theme) desktop/ |
stay editor |
internal / runtime-coupled |
Open questions / decisions to resolve at pickup
Candidate solutions (LIGHT — likely stale by pickup; re-evaluate)
All Vercel/Next-native, all keep the apex domain:
- Vercel Microfrontends (
microfrontends.json, edge-level routing, managed) — cleanest, editor = default app, www = child owning the enumerated paths. Paid: per routed request + per-project fee.
- Next.js Multi-Zones (DIY:
rewrites() + basePath + assetPrefix, editor as default zone) — no per-request fee; we hand-maintain the routing table + asset prefixes.
- Thin
vercel.json proxy project — smallest router variant.
Re-check when we pick this up — Vercel's offering here moves fast; there may be a better/cheaper option. Two non-negotiables regardless of tool: keep www a finite enumerated list (editor stays the fallback), and cross-zone links must be <a>, not <Link>.
Non-goals
- No
app.grida.co (or any product subdomain) — stay on the apex.
- Multi-tenant
{tenant}.grida.site / .grida.app routing is untouched; it stays with the editor (host-based, lib/tenant/).
- Not a rewrite of the marketing pages — a lift-and-shift of
(www) into its own deploy.
What
Split the www / marketing surface out of the
editorNext.js app into its own independently-deployed project, while keeping everything on the single apex domaingrida.co(noapp.grida.cosubdomain).The
editorapp carries far more than its name implies — landing, the entire marketing site, the editor runtime, the workspace/dashboard, APIs, and multi-tenant site rendering all live in one build.Current state (grounded —
editor/app/)Route groups today:
The
(www)group alone is a large public surface — each of these is a marketing/product page cluster:Meanwhile the product surfaces at root:
(workspace)/[org]/[proj]/...— the GitHub-style editor/workspace namespace(site)/organizations/[organization_name]/settings/billing/...— authed org pages(workbench)— the editor runtime{tenant}.grida.site/.grida.app, routed ineditor/lib/tenant/middleware.tsvia the app's proxy layer (isReservedAppHostname, platform-site canonicalization)editor/app/sitemap.tsat the app rootWhy
(www)/(pricing)currently rebuilds the entire editor (workbench, canvas, APIs). Split → two small, independent builds; marketing iterates without touching the editor pipeline. This is the primary motivation.editorstops being a catch-all;(www)'s ~15 page clusters stop diluting the editor's build graph.The constraint that makes this non-trivial
Both surfaces want root-level paths with no shared prefix:
grida.co/+grida.co/pricing+grida.co/svg(www) vsgrida.co/{org}/{proj}(editor). This is not a clean/docs-style prefix split.The resolution is forced:
{org}/{proj}is an unbounded catch-all, so it must be "everything not claimed."/,/pricing,/svg,/forms,/database, …).⇒ the www path list is a reserved-slug list in the editor's
[org]namespace (the GitHub reserved-username problem). Note we already carry this constraint inside the single app —grida.co/pricingandgrida.co/{org}already can't both be free. The split doesn't add the constraint; it promotes the reserved list into an explicit routing table. Whichever solution we pick, that table becomes the source of truth and must stay in sync with the[org]slug validator.Split boundary — starting classification (decide per-group at pickup)
(www)(+kr)(library)sitemap.ts; could be www or its own zone(brand)/(downloads)/(contact)(www)(site)(workspace)(workbench)(canvas)(api)(auth)(tenant)(tools)(preview)(embed)(insiders)(dev)(demo)(ingest)(theme)desktop/Open questions / decisions to resolve at pickup
app/sitemap.ts/robotslive after the split, and how do the two apps compose a single sitemap forgrida.co? Canonical URLs must stay stable (no marketing-page URL changes).[org]slug validator. Where does it live so it can't drift?.grida.coare shared across zones, but www is mostly logged-out; confirm no cookie/domain surprises and that cross-zone nav uses<a>(soft nav only works within a zone).www/components /@app/uialready shared via the monorepo; confirm both apps consume them cleanly (Turborepo cache boundaries).lib/tenant/without one shadowing the other.Candidate solutions (LIGHT — likely stale by pickup; re-evaluate)
All Vercel/Next-native, all keep the apex domain:
microfrontends.json, edge-level routing, managed) — cleanest, editor = default app, www = child owning the enumerated paths. Paid: per routed request + per-project fee.rewrites()+basePath+assetPrefix, editor as default zone) — no per-request fee; we hand-maintain the routing table + asset prefixes.vercel.jsonproxy project — smallest router variant.Non-goals
app.grida.co(or any product subdomain) — stay on the apex.{tenant}.grida.site/.grida.approuting is untouched; it stays with the editor (host-based,lib/tenant/).(www)into its own deploy.