CoreMVP

Project Structure

Understanding the codebase organization.

Overview

This template is one Next.js application. A single App Router catch-all mounts the embedded Hono API, while business logic stays in server-only services.

Directory Structure

[[...route]]/route.ts
layout.tsx
proxy.ts
app.ts

Key Directories

src/app/

Next.js App Router pages and the catch-all that hosts the Hono API.

PathPurpose
(marketing)/Landing and pricing pages
api/One [[...route]] adapter that passes /api/* requests to Hono
dashboard/Server-protected dashboard routes using the shared dashboard shell and navigation
demo/dashboard/Public fixed-data component preview with no customer, provider, or persistent data access
docs/Documentation pages
signin/, signup/Authentication pages

The Dashboard layout verifies the Supabase user on the server before it renders the shared sidebar and header. The authenticated Dashboard and public demo use the same DashboardSidebar component and item set; they provide different route prefixes, organization state, and user data. Activity and Records appear as subitems under Operations and reuse the public preview's fixed founder-revenue compositions. Authenticated Account, Billing, and enabled Organizations pages use the signed-in user's real state. Analytics, Activity, Records, Onboarding, Settings, and UI states remain clearly labelled component showcases when they use fixed data or local-only actions. Add or replace navigation in src/components/dashboard/dashboard-sidebar.tsx, then provide a real page for both route prefixes.

The default authenticated installation keeps the shared Organizations item visible but disabled. Enabling the complete Organizations schema activates that same item and replaces the application header with the real organization chooser.

The separate /demo/dashboard route previews the included dashboard compositions with a fixed dummy user and sample records. It is noindex, does not call auth, billing, Organizations, customer, or provider APIs, and does not persist its sample actions.

src/services/

Server-only business logic. These files use the "server-only" pragma to prevent client imports.

ServicePurpose
auth/Sign up, sign in, OAuth, and account updates
billing/Stripe checkout, portal, webhooks
user/User profile queries

src/api/

The embedded Hono app owns HTTP paths, methods, input parsing, cookies, headers, and responses. Domain modules call services; they do not own business or persistence rules.

PathPurpose
app.tsMounts domain routes and the small health, search, and test-capture endpoints
routes/auth.tsSupabase Auth HTTP endpoints
routes/billing.tsStripe checkout and portal endpoints
routes/user.tsPrivate account and billing readers
routes/webhooks.tsRaw Stripe webhook ingress

src/hooks/

Client-side React hooks for data fetching and state.

HookPurpose
auth/Session management, auth mutations
billing/Checkout, user status

src/lib/

Shared utilities and client configurations.

LibraryPurpose
supabase/Browser and server Supabase clients
stripe/Stripe client configuration

src/content/

MDX content for documentation and blog posts.


Data Flow

The browser calls the same-origin /api/* URL. The Next.js catch-all passes the request to Hono, the matching Hono handler calls a service, and the service uses the existing Supabase, Stripe, or repository owner.


Key Files

FilePurpose
src/app/layout.tsxRoot layout with providers
src/app/dashboard/layout.tsxServer-side Dashboard authentication admission and shared shell
src/app/dashboard/account/page.tsxDisplay-name and email settings
src/app/dashboard/billing/page.tsxPersisted access status and Stripe portal entry
src/components/dashboard/dashboard-sidebar.tsxShared authenticated and demo Dashboard navigation
src/app/api/[[...route]]/route.tsNext.js-to-Hono runtime adapter
src/api/app.tsCanonical /api/* route registry
src/proxy.tsRefreshes Supabase session cookies for matched requests
src/lib/supabase/server.tsServer-side Supabase client
src/lib/supabase/middleware.tsCookie refresh helper called by src/proxy.ts
src/services/billing/service.tsStripe checkout and portal logic
src/lib/source.tsFumadocs content source configuration

Services Pattern

Services use the "server-only" pragma to ensure they only run on the server:

src/services/auth/service.ts
import "server-only";

import { createSupabaseServerClient } from "@/lib/supabase/server";

export async function signUp({ email, password }) {
  const supabase = await createSupabaseServerClient();
  const { data, error } = await supabase.auth.signUp({ email, password });
  // ...
}

Hono routes import and call these services:

src/api/routes/auth.ts
import { Hono } from "hono";
import { signUp } from "@/services/auth";

export const authRoutes = new Hono();

authRoutes.post("/sign-up", async (c) => {
  const body = await c.req.json();
  const result = await signUp(body);
  return c.json(result, result.ok ? 200 : 400);
});

This pattern keeps business logic separate from HTTP handling while maintaining type safety.

Was this page helpful?

On this page