raxel.studio

Docs / Project structure

Project structure

The starter follows the Next.js App Router with two route groups: (public) for marketing/content pages and studio for the gated backoffice. The split is the most important convention to internalize.

Top-level layout #

app/
  (public)/        — marketing site, anyone can view
    layout.tsx     — public chrome (SiteHeader, SiteFooter, PageBackground)
    page.tsx       — homepage
    ...            — other public routes
  studio/          — backoffice, auth-gated
    layout.tsx     — studio chrome + session check
    ...            — admin pages
  sign-in/         — auth flow (public, no public chrome)
  api/             — route handlers (auth callbacks, etc.)
  layout.tsx       — root layout (font, html, body)
  globals.css
 
components/
  ui/              — generic primitives (Button, Input, …)
  section.tsx      — Container + Section layout primitives
  typography.tsx   — Display, Heading, Lede, Eyebrow, Pull
  site-header.tsx, site-footer.tsx
  ...
 
lib/
  auth.ts          — better-auth setup shared by client + server
  auth-server.ts   — server-only auth helpers
  auth-client.ts   — client-side auth helpers
  utils.ts         — `cn()` and other tiny helpers
 
db/                — Drizzle schema + migration output
docker/            — production Dockerfile + nginx
content/           — file-based content (markdown, JSON, etc.)

Why two route groups #

Route groups ((public) and studio) let each section have its own layout.tsx — its own chrome, its own background, its own session check — without affecting the URL. The home page is /, not /(public)/. The backoffice is /studio, not /(studio)/.

This matters because the public site and the backoffice are visually different applications but share the same component library. Two route groups + two layouts is how you keep them coherent without duplicating chrome.

Where to add things #

  • A new marketing page: create app/(public)/<your-route>/page.tsx. It inherits the public chrome automatically.
  • A new backoffice page: create app/studio/<your-route>/page.tsx. It inherits the studio layout, which checks the session and 401s if you're not signed in.
  • A new shared component: drop it in components/. If it's a generic primitive (button, input), components/ui/.
  • A new server-only helper: drop it in lib/. Use import "server-only" at the top if it must never run on the client.

Things that aren't there #

The starter does not include analytics, feature flags, error tracking, a CMS adapter, or a queue worker. Add them when you need them; each is one or two files in lib/ and an env var.