|
| 1 | +# Next.js App Router Template |
| 2 | + |
| 3 | +Fullstack [Next.js](https://nextjs.org/) project template using App Router. |
| 4 | + |
| 5 | +## Features |
| 6 | + |
| 7 | +- Based on new [Next.js](https://nextjs.org/) App Router and [Server Components](https://nextjs.org/docs/getting-started/react-essentials) |
| 8 | +- Internationalization (i18n) using [next-intl](https://next-intl-docs.vercel.app/) including support for Server Components |
| 9 | +- Type-safe keys for translation messages in React Components |
| 10 | +- Client-side data fetching with end-to-end type-safety using [tRPC](https://trpc.io/) + [superjson](https://github.com/blitz-js/superjson) + [React Query](https://tanstack.com/query) |
| 11 | +- Client-side form validation using [React Hook Form](https://www.react-hook-form.com/) + [Zod](https://zod.dev/) schemas |
| 12 | +- Data persistence using [Drizzle ORM](https://orm.drizzle.team/) including database migrations |
| 13 | +- Authentication using [NextAuth.js](https://next-auth.js.org/) with database session storage using [Drizzle ORM adapter](https://authjs.dev/reference/adapter/drizzle) |
| 14 | +- Personalized server-side rendering (using NextAuth.js session in Server Components) |
| 15 | +- Type-safe environment variables with validation using Zod (inspired by [Create T3 App](https://create.t3.gg/)) |
| 16 | + |
| 17 | +## Getting Started |
| 18 | + |
| 19 | +### Prepare Database |
| 20 | + |
| 21 | +The database is required for persistence of app data and NextAuth.js sessions. |
| 22 | + |
| 23 | +1. Install Docker. |
| 24 | +2. Run `pnpm db:run` to run the database |
| 25 | + |
| 26 | +### Prepare GitHub OAuth Client |
| 27 | + |
| 28 | +The OAuth client is required to sign in with GitHub account. You can swap providers in `src/server/auth.ts` if you want to use different identity providers. |
| 29 | + |
| 30 | +1. Go to <https://github.com/settings/apps>. |
| 31 | +2. Create a GitHub App. |
| 32 | + - Homepage URL: <http://localhost:3000> |
| 33 | + - Callback URL: <http://localhost:3000/api/auth/callback/github> |
| 34 | + - Account permissions - Email addresses: Read only |
| 35 | +3. Save the client ID and client secret for next step. |
| 36 | + |
| 37 | +### Create Local Environment |
| 38 | + |
| 39 | +1. Create a file `.env.local` in the project directory with the following variables. |
| 40 | + |
| 41 | + ```bash |
| 42 | + # Client ID of GitHub app |
| 43 | + GITHUB_CLIENT_ID=tobechanged |
| 44 | + # Client secret of GitHub app |
| 45 | + GITHUB_CLIENT_SECRET=tobechanged |
| 46 | + # Absolute base URL of Next.js app |
| 47 | + NEXTAUTH_URL=http://localhost:3000 |
| 48 | + # NextAuth.js secret, e.g. generate with "openssl rand -hex 32" |
| 49 | + NEXTAUTH_SECRET=tobechanged |
| 50 | + |
| 51 | + USE_LOCAL_DB=false |
| 52 | + # Planetscale DB connection settings |
| 53 | + DATABASE_HOST=tobechanged |
| 54 | + DATABASE_USERNAME=tobechanged |
| 55 | + DATABASE_PASSWORD=tobechanged |
| 56 | + ``` |
| 57 | + |
| 58 | +2. Install [pnpm](https://pnpm.io/) package manager. |
| 59 | +3. Run dependencies installation in the project directory. |
| 60 | + |
| 61 | + ```bash |
| 62 | + pnpm install |
| 63 | + ``` |
| 64 | + |
| 65 | +4. Run database migrations in the project directory. |
| 66 | + |
| 67 | + ```bash |
| 68 | + pnpm db:migrate |
| 69 | + ``` |
| 70 | + |
| 71 | +5. Run development server in the project directory. |
| 72 | + |
| 73 | + ```bash |
| 74 | + pnpm dev |
| 75 | + ``` |
| 76 | + |
| 77 | +Open <http://localhost:3000> with your browser. |
| 78 | + |
| 79 | +### Create Production Server |
| 80 | + |
| 81 | +1. Run production build in the project directory. |
| 82 | + |
| 83 | + ```bash |
| 84 | + pnpm build |
| 85 | + ``` |
| 86 | + |
| 87 | +2. Run production server in the project directory. |
| 88 | + |
| 89 | + ```bash |
| 90 | + pnpm start |
| 91 | + ``` |
| 92 | + |
| 93 | +## Project Structure |
| 94 | + |
| 95 | +### General Structure |
| 96 | + |
| 97 | +- `.vscode`: Project-specific configuration for Visual Studio Code. Contains a launch configuration for debugging in Chrome. |
| 98 | +- `drizzle`: Drizzle ORM migrations directory. Should only be modified using [Drizzle Kit](https://orm.drizzle.team/kit-docs/overview) commands. |
| 99 | +- `public`: Public assets like favicons to include in Next.js app. |
| 100 | +- `src/app`: Next.js app directory containing routes. See below for more details. |
| 101 | +- `src/components`: Contains React components shared by the whole Next.js app. |
| 102 | +- `src/messages`: Contains next-intl translation files for the supported locales. |
| 103 | +- `src/schemas`: Contains Zod schemas shared by tRPC procedures and client-side form validation. |
| 104 | +- `src/server`: Contains server-side implementation like tRPC router, Drizzle database client and NextAuth.js configuration. See below for more details. |
| 105 | +- `src/auth.ts`: Authentication-specific helpers shared by the whole Next.js app (client-side and server-side). |
| 106 | +- `src/env.mjs`: Provides type-safe access to environment variables. Variables must be declared here with appropriate Zod schema. |
| 107 | +- `src/globals.css`: Global stylesheet loaded by root layouts. |
| 108 | +- `src/i18n.ts`: Internationalization-specific configuration and helpers shared by the whole Next.js app (client-side and server-side). |
| 109 | +- `src/messages.d.ts`: Type declaration to enable type-safe keys for next-intl functions like `useTranslations`. Infers type from `src/messages/en.json`. |
| 110 | +- `src/middleware.ts`: Next.js middleware executed for every server request except API routes and static ressources. See below for more details. |
| 111 | +- `src/next-auth.d.ts`: Type declaration to augment NextAuth.js session interface to reflect user data provided by `session` callback in auth options. |
| 112 | +- `src/trpc.ts`: tRPC client based on React Query. Used for type-safe calls to tRPC procedures from React client components. |
| 113 | + |
| 114 | +### App Directory Structure |
| 115 | + |
| 116 | +- `src/app/[locale]`: Localized base route for all pages of the app. |
| 117 | + - `src/app/[locale]/_components`: Contains React components shared by all pages or layouts, e.g. page layout component with common React context providers. |
| 118 | + - `src/app/[locale]/_providers`: Contains React context providers shared by all pages or layouts. |
| 119 | + - `src/app/[locale]/(auth)`: Route group for authentication-related pages, e.g. sign-in page. |
| 120 | + - `src/app/[locale]/(auth)/layout.tsx`: Root layout component for authentication-related pages. Demonstrates how to apply different root layout to some pages. |
| 121 | + - `src/app/[locale]/(auth)/auth/signin`: Contains sign-in page component and its related React components. |
| 122 | + - `src/app/[locale]/(default)`: Route group for all other pages. |
| 123 | + - `src/app/[locale]/(default)/layout.tsx`: Root layout component for all other pages. |
| 124 | + - `src/app/[locale]/(default)/page.tsx`: Home page component. |
| 125 | + - `src/app/[locale]/(default)/todos`: Contains todos page component and its related React components and hooks. |
| 126 | +- `src/app/api`: Base route for all API endpoints of the app. |
| 127 | + - `src/app/api/auth/[...nextauth]/route.ts`: Route handler for NextAuth.js to process authentication. |
| 128 | + - `src/app/api/trpc/[trpc]/route.ts`: Route handler for tRPC to process calls to tRPC procedures. |
| 129 | + |
| 130 | +### Server Directory Structure |
| 131 | + |
| 132 | +- `src/server/api`: Contains tRPC routers implementing the tRPC procedures. |
| 133 | +- `src/server/api/router.ts`: Root API router merging all partial routers to one tRPC router. |
| 134 | +- `src/server/api/todos/router.ts`: Partial tRPC router for todos procedures. |
| 135 | +- `src/server/db`: Contains Drizzle ORM database client, schema definition and migration script. |
| 136 | +- `src/server/db/db.ts`: Drizzle ORM database client used to perform database operations in the app. |
| 137 | +- `src/server/db/migrate.ts`: Node.js script to run database migrations. |
| 138 | +- `src/server/db/schema.ts`: Drizzle ORM database schema defining tables and its relations. |
| 139 | +- `src/server/auth-i18n-middleware.ts`: Partial middleware function to handle i18n on sign-in page. See below for more details. |
| 140 | +- `src/server/auth.ts`: NextAuth.js configuration defining identity providers, database adapter and more settings. |
| 141 | +- `src/server/i18n-middleware.ts`: next-intl middleware with i18n configuration. |
| 142 | +- `src/server/i18n.ts`: next-intl server request config providing messages for React Server Components. |
| 143 | +- `src/server/trpc.ts`: tRPC server configuration with NextAuth.js session integration for protected procedures. |
| 144 | + |
| 145 | +### Middleware |
| 146 | + |
| 147 | +[Next.js middleware](https://nextjs.org/docs/app/building-your-application/routing/middleware) is required for two i18n-related features in this project. |
| 148 | + |
| 149 | +1. Since NextAuth.js has no concept for multi-language support on its pages yet invocations of `signIn()` will send users to the exact same route `/ca/auth/signin` (configured in NextAuth.js settings) no matter which locale they are currently using. Users coming from a locale other than `ca` would switch to Catalan on the sign-in page. The middleware handles this scenario by checking if the incoming request matches the sign-in page and contains a callback URL with a locale. If so, it extracts the locale from the callback URL (which is the original locale of the user) and redirects to the sign-in page using this original locale. Thus, users coming from the locale `en` will eventually land on `/en/auth/signin` and see the English version of the sign-in page. |
| 150 | +2. Next.js has dropped built-in support for internationalized routing with the app router. Instead, developers are supposed to [build their own solution](https://nextjs.org/docs/app/building-your-application/routing/internationalization) which involves creating middleware logic to handle redirects to the user's preferred language. Luckily, next-intl provides a middleware implementation to handle everything for us. |
| 151 | + |
| 152 | +## License |
| 153 | + |
| 154 | +[MIT](https://opensource.org/licenses/MIT) |
0 commit comments