create-nextjs-stack 0.1.1 → 0.1.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +502 -31
- package/package.json +6 -1
- package/templates/admin/app/(dashboard)/[resource]/[id]/page.tsx +6 -5
- package/templates/admin/app/(dashboard)/[resource]/new/page.tsx +11 -12
- package/templates/admin/app/(dashboard)/[resource]/page.tsx +4 -3
- package/templates/admin/app/actions/upload.ts +0 -7
- package/templates/admin/app/globals.css +112 -14
- package/templates/admin/app/layout.tsx +4 -1
- package/templates/admin/components/admin/Sidebar.tsx +2 -5
- package/templates/admin/components.json +22 -0
- package/templates/admin/hooks/useResource.ts +3 -0
- package/templates/admin/lib/services/resource.service.ts +2 -7
- package/templates/admin/lib/supabase/client.ts +8 -4
- package/templates/admin/lib/supabase/server.ts +1 -1
- package/templates/admin/lib/utils.ts +6 -0
- package/templates/admin/middleware.ts +1 -3
- package/templates/admin/next.config.ts +10 -2
- package/templates/admin/package-lock.json +13 -1
- package/templates/admin/package.json +11 -5
- package/templates/admin/src/lib/providers/StoreProvider.tsx +12 -0
- package/templates/admin/src/store/actions/index.ts +2 -0
- package/templates/admin/src/store/hooks.ts +11 -0
- package/templates/admin/src/store/index.ts +17 -0
- package/templates/admin/src/store/reducers/index.ts +11 -0
- package/templates/admin/src/store/types/index.ts +2 -0
- package/templates/admin/tsconfig.json +1 -1
- package/templates/web/.env.example +5 -1
- package/templates/web/package-lock.json +49 -18
- package/templates/web/package.json +3 -4
- package/templates/web/postcss.config.mjs +3 -1
- package/templates/web/src/app/api/revalidate/route.ts +46 -87
- package/templates/web/src/app/globals.css +1 -13
- package/templates/web/src/app/layout.tsx +4 -46
- package/templates/web/src/app/robots.ts +1 -1
- package/templates/web/src/app/sitemap.ts +27 -31
- package/templates/web/src/lib/seo/metadata.ts +5 -5
- package/templates/web/src/lib/seo/seo.config.ts +55 -59
- package/templates/web/src/lib/seo/seo.types.ts +1 -7
- package/templates/web/src/lib/services/categories.service.ts +3 -3
- package/templates/web/src/lib/services/clients.service.ts +2 -2
- package/templates/web/src/lib/services/products.service.ts +3 -3
- package/templates/web/src/lib/services/projects.service.ts +3 -3
- package/templates/web/src/lib/services/users.service.ts +2 -2
- package/templates/web/src/lib/supabase/client.ts +1 -1
- package/templates/web/src/lib/supabase/server.ts +1 -1
- package/templates/web/src/store/hooks.ts +11 -0
- package/templates/web/src/store/index.ts +11 -7
- package/templates/web/src/store/reducers/index.ts +1 -3
- package/templates/admin/app/(dashboard)/categories/[id]/page.tsx +0 -22
- package/templates/admin/app/(dashboard)/categories/new/page.tsx +0 -5
- package/templates/admin/app/(dashboard)/categories/page.tsx +0 -33
- package/templates/admin/app/(dashboard)/clients/[id]/page.tsx +0 -22
- package/templates/admin/app/(dashboard)/clients/new/page.tsx +0 -5
- package/templates/admin/app/(dashboard)/clients/page.tsx +0 -33
- package/templates/admin/app/(dashboard)/products/[id]/page.tsx +0 -22
- package/templates/admin/app/(dashboard)/products/new/page.tsx +0 -5
- package/templates/admin/app/(dashboard)/products/page.tsx +0 -33
- package/templates/admin/app/(dashboard)/projects/[id]/page.tsx +0 -22
- package/templates/admin/app/(dashboard)/projects/new/page.tsx +0 -5
- package/templates/admin/app/(dashboard)/projects/page.tsx +0 -33
- package/templates/admin/app/(dashboard)/users/[id]/page.tsx +0 -22
- package/templates/admin/app/(dashboard)/users/new/page.tsx +0 -5
- package/templates/admin/app/(dashboard)/users/page.tsx +0 -33
- package/templates/admin/components/categories/CategoryForm.tsx +0 -24
- package/templates/admin/components/categories/CategoryList.tsx +0 -113
- package/templates/admin/components/clients/ClientForm.tsx +0 -24
- package/templates/admin/components/clients/ClientList.tsx +0 -113
- package/templates/admin/components/products/ProductForm.tsx +0 -24
- package/templates/admin/components/products/ProductList.tsx +0 -117
- package/templates/admin/components/projects/ProjectForm.tsx +0 -24
- package/templates/admin/components/projects/ProjectList.tsx +0 -121
- package/templates/admin/components/users/UserForm.tsx +0 -39
- package/templates/admin/components/users/UserList.tsx +0 -101
- package/templates/web/src/lib/services/categoryService.ts +0 -251
- package/templates/web/src/lib/services/clientService.ts +0 -132
- package/templates/web/src/lib/services/productService.ts +0 -261
- package/templates/web/src/lib/services/projectService.ts +0 -234
- package/templates/web/src/lib/utils/cache.ts +0 -98
- package/templates/web/src/lib/utils/rate-limiter.ts +0 -102
package/README.md
CHANGED
|
@@ -1,60 +1,531 @@
|
|
|
1
|
-
|
|
1
|
+
<div align="center">
|
|
2
2
|
|
|
3
|
-
|
|
4
|
-
[](https://opensource.org/licenses/MIT)
|
|
5
|
-
[](https://www.npmjs.com/package/create-nextjs-stack)
|
|
3
|
+
# create-nextjs-stack
|
|
6
4
|
|
|
7
|
-
|
|
5
|
+
[](https://www.npmjs.com/package/create-nextjs-stack)
|
|
6
|
+
[](https://www.npmjs.com/package/create-nextjs-stack)
|
|
7
|
+
[](https://opensource.org/licenses/MIT)
|
|
8
|
+
[](https://nodejs.org/)
|
|
8
9
|
|
|
9
|
-
|
|
10
|
+
**A zero-config CLI to scaffold production-ready Next.js applications.**
|
|
11
|
+
Choose between a marketing landing page, a Supabase admin panel, or both — in one command.
|
|
10
12
|
|
|
11
|
-
-
|
|
12
|
-
- **Production Ready**: Includes Tailwind CSS 4, Redux Toolkit, Supabase, Cloudinary, and Resend.
|
|
13
|
-
- **Smart Scaffolding**: Automatically handles environment variables and cleans up dependencies.
|
|
13
|
+
[Quick Start](#-quick-start) · [Templates](#-templates) · [Project Structure](#-project-structure) · [Environment Variables](#-environment-variables) · [Deployment](#-deployment) · [Contributing](#-contributing)
|
|
14
14
|
|
|
15
|
-
|
|
15
|
+
</div>
|
|
16
16
|
|
|
17
|
-
|
|
17
|
+
---
|
|
18
|
+
|
|
19
|
+
## Table of Contents
|
|
20
|
+
|
|
21
|
+
- [Overview](#-overview)
|
|
22
|
+
- [Quick Start](#-quick-start)
|
|
23
|
+
- [CLI Reference](#-cli-reference)
|
|
24
|
+
- [Templates](#-templates)
|
|
25
|
+
- [Web — Landing Page](#-web--landing-page)
|
|
26
|
+
- [Admin — Supabase Panel](#-admin--supabase-admin-panel)
|
|
27
|
+
- [Full Stack](#-full-stack)
|
|
28
|
+
- [Project Structure](#-project-structure)
|
|
29
|
+
- [Web Template Structure](#web-template)
|
|
30
|
+
- [Admin Template Structure](#admin-template)
|
|
31
|
+
- [Environment Variables](#-environment-variables)
|
|
32
|
+
- [Web Template](#web-template-env)
|
|
33
|
+
- [Admin Template](#admin-template-env)
|
|
34
|
+
- [Development](#-development)
|
|
35
|
+
- [Deployment](#-deployment)
|
|
36
|
+
- [FAQ](#-faq)
|
|
37
|
+
- [Contributing](#-contributing)
|
|
38
|
+
- [Changelog](#-changelog)
|
|
39
|
+
- [License](#-license)
|
|
40
|
+
|
|
41
|
+
---
|
|
42
|
+
|
|
43
|
+
## 🔍 Overview
|
|
44
|
+
|
|
45
|
+
**`create-nextjs-stack`** handles the tedious setup so that you can start building immediately. In a single command it:
|
|
46
|
+
|
|
47
|
+
- Scaffolds a fully configured Next.js 16 application
|
|
48
|
+
- Copies `.env.example` to `.env` so credentials are ready to fill
|
|
49
|
+
- Sets the project name inside `package.json` automatically
|
|
50
|
+
- Prints exact next steps so you never have to guess
|
|
51
|
+
|
|
52
|
+
The result is a codebase that follows real-world best practices — App Router, TypeScript, Tailwind CSS 4, server-side Supabase auth, SEO metadata, and more — without any manual wiring.
|
|
53
|
+
|
|
54
|
+
---
|
|
55
|
+
|
|
56
|
+
## ⚡ Quick Start
|
|
18
57
|
|
|
19
58
|
```bash
|
|
20
|
-
npx
|
|
59
|
+
# Using npx (no install required)
|
|
60
|
+
npx create-nextjs-stack@latest my-app
|
|
61
|
+
|
|
62
|
+
# Using npm
|
|
63
|
+
npm create nextjs-stack my-app
|
|
64
|
+
|
|
65
|
+
# Global install (optional)
|
|
66
|
+
npm install -g create-nextjs-stack
|
|
67
|
+
create-nextjs-stack my-app
|
|
68
|
+
```
|
|
69
|
+
|
|
70
|
+
The interactive CLI will guide you:
|
|
71
|
+
|
|
72
|
+
```
|
|
73
|
+
? What is your project named? › my-app
|
|
74
|
+
? Which template would you like to generate?
|
|
75
|
+
❯ Full Stack (Web + Admin)
|
|
76
|
+
Web Only (Next.js Landing)
|
|
77
|
+
Admin Only (Supabase Admin)
|
|
78
|
+
```
|
|
79
|
+
|
|
80
|
+
After scaffolding:
|
|
81
|
+
|
|
82
|
+
```bash
|
|
83
|
+
cd my-app
|
|
84
|
+
npm install # install dependencies
|
|
85
|
+
|
|
86
|
+
# Open .env and fill in your credentials, then:
|
|
87
|
+
npm run dev # start development server at http://localhost:3000
|
|
21
88
|
```
|
|
22
89
|
|
|
23
|
-
|
|
90
|
+
---
|
|
24
91
|
|
|
25
|
-
|
|
92
|
+
## 🖥 CLI Reference
|
|
26
93
|
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
- `Full Stack`: Creates both `web` and `admin` projects.
|
|
30
|
-
- `Web Only`: Creates the Next.js Landing website.
|
|
31
|
-
- `Admin Only`: Creates the Supabase Admin Panel.
|
|
94
|
+
```
|
|
95
|
+
Usage: create-nextjs-stack [project-directory] [options]
|
|
32
96
|
|
|
33
|
-
|
|
97
|
+
Arguments:
|
|
98
|
+
project-directory Target directory for the new project (optional, prompted if omitted)
|
|
34
99
|
|
|
35
|
-
|
|
100
|
+
Options:
|
|
101
|
+
-t, --template <type> Template to scaffold: web | admin | full-stack
|
|
102
|
+
-v, --version Print CLI version
|
|
103
|
+
-h, --help Show help
|
|
104
|
+
```
|
|
105
|
+
|
|
106
|
+
### Examples
|
|
36
107
|
|
|
37
108
|
```bash
|
|
38
|
-
#
|
|
109
|
+
# Interactive — prompts for name and template
|
|
110
|
+
npx create-nextjs-stack
|
|
111
|
+
|
|
112
|
+
# Named project, interactive template selection
|
|
113
|
+
npx create-nextjs-stack my-app
|
|
114
|
+
|
|
115
|
+
# Fully non-interactive
|
|
116
|
+
npx create-nextjs-stack my-app --template web
|
|
117
|
+
npx create-nextjs-stack my-app --template admin
|
|
39
118
|
npx create-nextjs-stack my-app --template full-stack
|
|
119
|
+
```
|
|
40
120
|
|
|
41
|
-
|
|
42
|
-
npx create-nextjs-stack my-web-app --template web
|
|
121
|
+
### Overwrite Behaviour
|
|
43
122
|
|
|
44
|
-
|
|
45
|
-
|
|
123
|
+
If the target directory already exists and is non-empty, the CLI will ask:
|
|
124
|
+
|
|
125
|
+
```
|
|
126
|
+
Directory my-app is not empty. Overwrite? (y/N)
|
|
46
127
|
```
|
|
47
128
|
|
|
48
|
-
|
|
129
|
+
If you confirm, the directory is emptied before scaffolding. If you decline, the process aborts safely.
|
|
130
|
+
|
|
131
|
+
---
|
|
132
|
+
|
|
133
|
+
## 📦 Templates
|
|
134
|
+
|
|
135
|
+
### 🌐 Web — Landing Page
|
|
136
|
+
|
|
137
|
+
A production-ready Next.js marketing website starter.
|
|
49
138
|
|
|
50
|
-
|
|
139
|
+
#### Tech Stack
|
|
140
|
+
|
|
141
|
+
| Layer | Technology | Notes |
|
|
142
|
+
| ---------------- | ----------------------------------------------------------------------------------------------- | ---------------------------- |
|
|
143
|
+
| Framework | [Next.js 16](https://nextjs.org/) | App Router, Turbopack |
|
|
144
|
+
| Language | TypeScript 5 | Strict mode |
|
|
145
|
+
| Styling | [Tailwind CSS 4](https://tailwindcss.com/) | `@tailwindcss/postcss` |
|
|
146
|
+
| State Management | [Redux Toolkit](https://redux-toolkit.js.org/) | Typed slices + actions |
|
|
147
|
+
| Database & Auth | [Supabase](https://supabase.com/) | PostgreSQL + SSR auth |
|
|
148
|
+
| Media | [Cloudinary](https://cloudinary.com/) + `next-cloudinary` | Optimized image delivery |
|
|
149
|
+
| Email | [Resend](https://resend.com/) | Transactional emails |
|
|
150
|
+
| Analytics | [Google Analytics](https://analytics.google.com/) | Via `@next/third-parties` |
|
|
151
|
+
| Forms | [React Hook Form](https://react-hook-form.com/) + [Zod](https://zod.dev/) | Schema validation |
|
|
152
|
+
| Animations | [Framer Motion](https://www.framer.com/motion/) | Page & component transitions |
|
|
153
|
+
| Icons | [Lucide React](https://lucide.dev/) + [React Icons](https://react-icons.github.io/react-icons/) | |
|
|
154
|
+
|
|
155
|
+
#### Feature Highlights
|
|
156
|
+
|
|
157
|
+
- **⚡ Turbopack** for sub-second dev rebuilds and faster production builds
|
|
158
|
+
- **🔍 Full SEO Suite** — dynamic `metadata` API, `sitemap.ts`, `robots.ts`, canonical URLs, and Open Graph tags all configurable from environment variables
|
|
159
|
+
- **🎯 Service Layer** — all external API calls go through `src/lib/services/`, keeping components clean
|
|
160
|
+
- **🗄 Supabase SSR** — server-side Supabase client with cookie-based session handling, compatible with Next.js App Router
|
|
161
|
+
- **🖼 Cloudinary Integration** — ready-to-use `CldImage` and `CldUploadWidget` components via `next-cloudinary`
|
|
162
|
+
- **📬 Email Service** — Resend integration with typed email helpers in the service layer
|
|
163
|
+
- **🔄 Redux Store** — fully typed store with actions, reducers, and providers already wired in
|
|
164
|
+
- **📱 Responsive** — mobile-first layout with Tailwind utilities
|
|
165
|
+
- **🌐 i18n Ready** — folder structure supports multi-language routing expansion
|
|
166
|
+
|
|
167
|
+
---
|
|
168
|
+
|
|
169
|
+
### 🛠 Admin — Supabase Admin Panel
|
|
170
|
+
|
|
171
|
+
A minimal, extensible admin dashboard for managing your Supabase data.
|
|
172
|
+
|
|
173
|
+
#### Tech Stack
|
|
174
|
+
|
|
175
|
+
| Layer | Technology | Notes |
|
|
176
|
+
| --------------- | ----------------------------------------------------------- | ------------------------- |
|
|
177
|
+
| Framework | [Next.js 16](https://nextjs.org/) | App Router |
|
|
178
|
+
| Language | TypeScript 5 | |
|
|
179
|
+
| Styling | [Tailwind CSS 4](https://tailwindcss.com/) | `tailwind-merge` + `clsx` |
|
|
180
|
+
| Database & Auth | [Supabase](https://supabase.com/) | PostgreSQL + SSR auth |
|
|
181
|
+
| Media | [Cloudinary](https://cloudinary.com/) | Image uploads |
|
|
182
|
+
| Forms | [React Hook Form](https://react-hook-form.com/) | |
|
|
183
|
+
| Notifications | [React Toastify](https://fkhadra.github.io/react-toastify/) | Toast alerts |
|
|
184
|
+
| Icons | [Lucide React](https://lucide.dev/) | |
|
|
185
|
+
| Utilities | `clsx`, `tailwind-merge` | Class merging helpers |
|
|
186
|
+
|
|
187
|
+
#### Feature Highlights
|
|
188
|
+
|
|
189
|
+
- **🔐 Server-side Auth** — Supabase SSR client; sessions stored in HTTP-only cookies
|
|
190
|
+
- **🛡 Route Protection** — `middleware.ts` guards all dashboard routes; unauthenticated users are redirected to `/login`
|
|
191
|
+
- **📊 Dashboard Layout** — sidebar + header shell with nested route groups `(auth)` and `(dashboard)`
|
|
192
|
+
- **⚙ Server Actions** — data mutations use Next.js Server Actions inside `app/actions/`, keeping client bundles small
|
|
193
|
+
- **🔔 Toast Notifications** — React Toastify integrated at the root layout for global alerts
|
|
194
|
+
- **📷 Cloudinary Uploads** — image upload utilities pre-configured
|
|
195
|
+
- **🧱 Component Library** — reusable admin-specific components in `components/admin/`
|
|
196
|
+
|
|
197
|
+
---
|
|
198
|
+
|
|
199
|
+
### 🏗 Full Stack
|
|
200
|
+
|
|
201
|
+
The `full-stack` template scaffolds both the Web and Admin templates into two independent subdirectories under a shared root:
|
|
51
202
|
|
|
52
203
|
```
|
|
53
204
|
my-app/
|
|
54
|
-
├── web/
|
|
55
|
-
└── admin/
|
|
205
|
+
├── web/ ← Next.js landing page (port 3000)
|
|
206
|
+
└── admin/ ← Supabase admin panel (port 3001)
|
|
56
207
|
```
|
|
57
208
|
|
|
209
|
+
Each sub-project is **completely independent** — separate `package.json`, separate `.env`, separate `node_modules` and dev server. There is no shared monorepo config by design; this keeps the scaffold simple and avoids coupling.
|
|
210
|
+
|
|
211
|
+
> **Tip:** Run each project in a separate terminal with `npm run dev`. If ports conflict, pass `-- --port 3001` to the admin project.
|
|
212
|
+
|
|
213
|
+
---
|
|
214
|
+
|
|
215
|
+
## 📁 Project Structure
|
|
216
|
+
|
|
217
|
+
### Web Template
|
|
218
|
+
|
|
219
|
+
```
|
|
220
|
+
my-app/
|
|
221
|
+
├── public/
|
|
222
|
+
│ ├── og-image.png # Default Open Graph image
|
|
223
|
+
│ └── favicon.ico
|
|
224
|
+
│
|
|
225
|
+
├── src/
|
|
226
|
+
│ ├── app/ # Next.js App Router
|
|
227
|
+
│ │ ├── layout.tsx # Root layout — fonts, providers, metadata
|
|
228
|
+
│ │ ├── page.tsx # Homepage
|
|
229
|
+
│ │ ├── robots.ts # Dynamic robots.txt generator
|
|
230
|
+
│ │ ├── sitemap.ts # Dynamic XML sitemap generator
|
|
231
|
+
│ │ └── api/ # API route handlers
|
|
232
|
+
│ │
|
|
233
|
+
│ ├── components/ # Shared UI components
|
|
234
|
+
│ │
|
|
235
|
+
│ ├── hooks/ # Custom React hooks
|
|
236
|
+
│ │
|
|
237
|
+
│ ├── lib/
|
|
238
|
+
│ │ ├── providers/
|
|
239
|
+
│ │ │ └── ReduxProvider.tsx # Wraps app with Redux store
|
|
240
|
+
│ │ ├── seo/
|
|
241
|
+
│ │ │ ├── seo.config.ts # Centralised SEO defaults
|
|
242
|
+
│ │ │ ├── metadata.ts # Page metadata helpers
|
|
243
|
+
│ │ │ └── structured-data.ts # JSON-LD schema helpers
|
|
244
|
+
│ │ ├── services/
|
|
245
|
+
│ │ │ ├── email.service.ts # Resend email helpers
|
|
246
|
+
│ │ │ ├── storage.service.ts # Cloudinary upload helpers
|
|
247
|
+
│ │ │ └── supabase.service.ts # Supabase query helpers
|
|
248
|
+
│ │ ├── supabase/
|
|
249
|
+
│ │ │ ├── client.ts # Browser Supabase client
|
|
250
|
+
│ │ │ ├── server.ts # Server Supabase client (SSR)
|
|
251
|
+
│ │ │ └── middleware.ts # Session refresh helper
|
|
252
|
+
│ │ └── utils/ # Shared utility functions
|
|
253
|
+
│ │
|
|
254
|
+
│ └── store/ # Redux Toolkit store
|
|
255
|
+
│ ├── index.ts # Store configuration
|
|
256
|
+
│ ├── actions/ # Action creators
|
|
257
|
+
│ ├── reducers/ # Slice reducers
|
|
258
|
+
│ └── types/ # Store-wide TypeScript types
|
|
259
|
+
│
|
|
260
|
+
├── .env.example # All required env vars with descriptions
|
|
261
|
+
├── components.json # shadcn/ui config (if used)
|
|
262
|
+
├── next.config.ts
|
|
263
|
+
├── postcss.config.mjs # Tailwind CSS 4 PostCSS config
|
|
264
|
+
└── tsconfig.json
|
|
265
|
+
```
|
|
266
|
+
|
|
267
|
+
### Admin Template
|
|
268
|
+
|
|
269
|
+
```
|
|
270
|
+
my-admin/
|
|
271
|
+
├── public/
|
|
272
|
+
│
|
|
273
|
+
├── app/ # Next.js App Router (no src/ wrapper)
|
|
274
|
+
│ ├── layout.tsx # Root layout — Toastify provider
|
|
275
|
+
│ ├── page.tsx # Redirects to /dashboard
|
|
276
|
+
│ ├── globals.css # Tailwind CSS 4 imports + theme tokens
|
|
277
|
+
│ │
|
|
278
|
+
│ ├── (auth)/ # Unauthenticated routes
|
|
279
|
+
│ │ └── login/
|
|
280
|
+
│ │ └── page.tsx # Login page
|
|
281
|
+
│ │
|
|
282
|
+
│ ├── (dashboard)/ # Protected routes (guarded by middleware)
|
|
283
|
+
│ │ ├── layout.tsx # Dashboard shell (sidebar + header)
|
|
284
|
+
│ │ ├── dashboard/ # Main dashboard page
|
|
285
|
+
│ │ ├── users/ # User management
|
|
286
|
+
│ │ ├── content/ # Content management
|
|
287
|
+
│ │ └── settings/ # App settings
|
|
288
|
+
│ │
|
|
289
|
+
│ └── actions/ # Next.js Server Actions
|
|
290
|
+
│ ├── auth.actions.ts # Login / logout / session
|
|
291
|
+
│ └── data.actions.ts # CRUD operations
|
|
292
|
+
│
|
|
293
|
+
├── components/
|
|
294
|
+
│ └── admin/ # Admin-specific components
|
|
295
|
+
│ ├── Sidebar.tsx
|
|
296
|
+
│ ├── Header.tsx
|
|
297
|
+
│ ├── DataTable.tsx
|
|
298
|
+
│ └── ...
|
|
299
|
+
│
|
|
300
|
+
├── config/
|
|
301
|
+
│ └── navigation.ts # Sidebar navigation config
|
|
302
|
+
│
|
|
303
|
+
├── hooks/ # Custom hooks
|
|
304
|
+
│
|
|
305
|
+
├── lib/
|
|
306
|
+
│ ├── supabase/
|
|
307
|
+
│ │ ├── client.ts # Browser Supabase client
|
|
308
|
+
│ │ └── server.ts # Server Supabase client (SSR)
|
|
309
|
+
│ └── utils/ # Shared helpers (cn, formatters…)
|
|
310
|
+
│
|
|
311
|
+
├── middleware.ts # Route protection — redirects to /login
|
|
312
|
+
├── .env.example
|
|
313
|
+
├── next.config.ts
|
|
314
|
+
├── postcss.config.mjs
|
|
315
|
+
└── tsconfig.json
|
|
316
|
+
```
|
|
317
|
+
|
|
318
|
+
---
|
|
319
|
+
|
|
320
|
+
## 🔑 Environment Variables
|
|
321
|
+
|
|
322
|
+
The CLI automatically copies `.env.example` → `.env` during scaffolding. Open `.env` and replace the placeholder values with your real credentials.
|
|
323
|
+
|
|
324
|
+
### Web Template Env
|
|
325
|
+
|
|
326
|
+
```bash
|
|
327
|
+
# ─── Email (Resend) ────────────────────────────────────────────────────────────
|
|
328
|
+
# https://resend.com → API Keys
|
|
329
|
+
RESEND_API_KEY=re_xxxxxxxxxxxxxxxxxxxx
|
|
330
|
+
# The verified sender address configured in your Resend domain
|
|
331
|
+
RESEND_FROM_EMAIL=hello@yourdomain.com
|
|
332
|
+
|
|
333
|
+
# ─── Supabase ──────────────────────────────────────────────────────────────────
|
|
334
|
+
# https://supabase.com → Project Settings → API
|
|
335
|
+
NEXT_PUBLIC_SUPABASE_URL=https://xxxxxxxxxxxx.supabase.co
|
|
336
|
+
NEXT_PUBLIC_SUPABASE_ANON_KEY=eyJhbGciOiJIUzI1NiIsIn...
|
|
337
|
+
SUPABASE_SERVICE_ROLE_KEY=eyJhbGciOiJIUzI1NiIsIn... # Never expose this client-side!
|
|
338
|
+
|
|
339
|
+
# Supabase project meta (used by Supabase CLI / migrations)
|
|
340
|
+
SUPABASE_PROJECT_ID=xxxxxxxxxxxx
|
|
341
|
+
SUPABASE_PROJECT_NAME=my-project
|
|
342
|
+
SUPABASE_DATABASE_PASSWORD=your-db-password
|
|
343
|
+
|
|
344
|
+
# Used to verify on-demand revalidation requests
|
|
345
|
+
REVALIDATION_SECRET=a-random-secret-string
|
|
346
|
+
|
|
347
|
+
# ─── Cloudinary ────────────────────────────────────────────────────────────────
|
|
348
|
+
# https://cloudinary.com → Dashboard
|
|
349
|
+
NEXT_PUBLIC_CLOUDINARY_CLOUD_NAME=your-cloud-name
|
|
350
|
+
CLOUDINARY_API_KEY=000000000000000
|
|
351
|
+
CLOUDINARY_API_SECRET=xxxxxxxxxxxxxxxxxxxxxxxxxxxx
|
|
352
|
+
CLOUDINARY_ID=your-cloud-name # Same as CLOUD_NAME, for SDK compat
|
|
353
|
+
CLOUDINARY_URL=cloudinary://API_KEY:API_SECRET@CLOUD_NAME
|
|
354
|
+
|
|
355
|
+
# ─── Site ──────────────────────────────────────────────────────────────────────
|
|
356
|
+
NEXT_PUBLIC_SITE_URL=https://yourdomain.com # Used for canonical URLs & OG tags
|
|
357
|
+
NEXT_PUBLIC_GA_ID=G-XXXXXXXXXX # Google Analytics Measurement ID
|
|
358
|
+
```
|
|
359
|
+
|
|
360
|
+
### Admin Template Env
|
|
361
|
+
|
|
362
|
+
```bash
|
|
363
|
+
# ─── Supabase ──────────────────────────────────────────────────────────────────
|
|
364
|
+
NEXT_PUBLIC_SUPABASE_URL=https://xxxxxxxxxxxx.supabase.co
|
|
365
|
+
NEXT_PUBLIC_SUPABASE_ANON_KEY=eyJhbGciOiJIUzI1NiIsIn...
|
|
366
|
+
SUPABASE_SERVICE_ROLE_KEY=eyJhbGciOiJIUzI1NiIsIn... # Server-side only
|
|
367
|
+
|
|
368
|
+
# ─── Cloudinary ────────────────────────────────────────────────────────────────
|
|
369
|
+
NEXT_PUBLIC_CLOUDINARY_CLOUD_NAME=your-cloud-name
|
|
370
|
+
CLOUDINARY_API_KEY=000000000000000
|
|
371
|
+
CLOUDINARY_API_SECRET=xxxxxxxxxxxxxxxxxxxxxxxxxxxx
|
|
372
|
+
CLOUDINARY_URL=cloudinary://API_KEY:API_SECRET@CLOUD_NAME
|
|
373
|
+
```
|
|
374
|
+
|
|
375
|
+
> ⚠️ **Security:** Variables prefixed with `NEXT_PUBLIC_` are bundled into the client. Never prefix `SERVICE_ROLE_KEY` or `API_SECRET` with `NEXT_PUBLIC_`.
|
|
376
|
+
|
|
377
|
+
---
|
|
378
|
+
|
|
379
|
+
## 🛠 Development
|
|
380
|
+
|
|
381
|
+
### Prerequisites
|
|
382
|
+
|
|
383
|
+
| Tool | Minimum Version |
|
|
384
|
+
| ------- | --------------- |
|
|
385
|
+
| Node.js | 18.x |
|
|
386
|
+
| npm | 9.x |
|
|
387
|
+
|
|
388
|
+
### Available Scripts
|
|
389
|
+
|
|
390
|
+
Both templates share the same script interface:
|
|
391
|
+
|
|
392
|
+
```bash
|
|
393
|
+
npm run dev # Start dev server (Web uses Turbopack: next dev --turbopack)
|
|
394
|
+
npm run build # Compile for production
|
|
395
|
+
npm run start # Serve the production build
|
|
396
|
+
npm run lint # Run ESLint across the project
|
|
397
|
+
```
|
|
398
|
+
|
|
399
|
+
### Third-party Account Setup
|
|
400
|
+
|
|
401
|
+
| Service | Free Tier | Setup Steps |
|
|
402
|
+
| ------------------------------------------------ | --------- | ----------------------------------------------------------------------- |
|
|
403
|
+
| [Supabase](https://supabase.com) | ✅ Yes | Create project → copy URL and anon key from **Project Settings → API** |
|
|
404
|
+
| [Cloudinary](https://cloudinary.com) | ✅ Yes | Create account → copy cloud name and API credentials from **Dashboard** |
|
|
405
|
+
| [Resend](https://resend.com) | ✅ Yes | Create account → add domain (or use sandbox) → create API key |
|
|
406
|
+
| [Google Analytics](https://analytics.google.com) | ✅ Yes | Create property → copy Measurement ID (`G-XXXXXXXXXX`) |
|
|
407
|
+
|
|
408
|
+
---
|
|
409
|
+
|
|
410
|
+
## 🚢 Deployment
|
|
411
|
+
|
|
412
|
+
### Vercel (Recommended)
|
|
413
|
+
|
|
414
|
+
The Web template is optimised for Vercel — App Router, Edge Middleware, and Supabase SSR all work without any additional configuration.
|
|
415
|
+
|
|
416
|
+
1. Push your project to GitHub, GitLab, or Bitbucket.
|
|
417
|
+
2. Go to [vercel.com/new](https://vercel.com/new) and import the repository.
|
|
418
|
+
3. Add all environment variables from your `.env` file via the **Environment Variables** panel.
|
|
419
|
+
4. Click **Deploy**.
|
|
420
|
+
|
|
421
|
+
> **Full Stack:** Deploy `web/` and `admin/` as **separate Vercel projects** pointing to different subdirectories. In each project's settings, set the **Root Directory** to `web` or `admin` respectively.
|
|
422
|
+
|
|
423
|
+
### Netlify
|
|
424
|
+
|
|
425
|
+
```bash
|
|
426
|
+
# Build command
|
|
427
|
+
npm run build
|
|
428
|
+
|
|
429
|
+
# Publish directory
|
|
430
|
+
.next
|
|
431
|
+
```
|
|
432
|
+
|
|
433
|
+
Add a `netlify.toml` at the project root:
|
|
434
|
+
|
|
435
|
+
```toml
|
|
436
|
+
[build]
|
|
437
|
+
command = "npm run build"
|
|
438
|
+
publish = ".next"
|
|
439
|
+
|
|
440
|
+
[[plugins]]
|
|
441
|
+
package = "@netlify/plugin-nextjs"
|
|
442
|
+
```
|
|
443
|
+
|
|
444
|
+
### Railway / Render / Other Node hosts
|
|
445
|
+
|
|
446
|
+
These platforms detect Next.js automatically. Ensure your environment variables are configured in the platform's dashboard, then connect your repository and deploy.
|
|
447
|
+
|
|
448
|
+
### Docker (Self-hosted)
|
|
449
|
+
|
|
450
|
+
```dockerfile
|
|
451
|
+
FROM node:20-alpine AS deps
|
|
452
|
+
WORKDIR /app
|
|
453
|
+
COPY package*.json ./
|
|
454
|
+
RUN npm ci
|
|
455
|
+
|
|
456
|
+
FROM node:20-alpine AS builder
|
|
457
|
+
WORKDIR /app
|
|
458
|
+
COPY --from=deps /app/node_modules ./node_modules
|
|
459
|
+
COPY . .
|
|
460
|
+
RUN npm run build
|
|
461
|
+
|
|
462
|
+
FROM node:20-alpine AS runner
|
|
463
|
+
WORKDIR /app
|
|
464
|
+
ENV NODE_ENV=production
|
|
465
|
+
COPY --from=builder /app/.next/standalone ./
|
|
466
|
+
COPY --from=builder /app/.next/static ./.next/static
|
|
467
|
+
COPY --from=builder /app/public ./public
|
|
468
|
+
EXPOSE 3000
|
|
469
|
+
CMD ["node", "server.js"]
|
|
470
|
+
```
|
|
471
|
+
|
|
472
|
+
> Enable `output: 'standalone'` in `next.config.ts` when using Docker.
|
|
473
|
+
|
|
474
|
+
---
|
|
475
|
+
|
|
476
|
+
## ❓ FAQ
|
|
477
|
+
|
|
478
|
+
**Q: Can I use JavaScript instead of TypeScript?**
|
|
479
|
+
A: Not yet — TypeScript only for now. A `--javascript` flag is planned for a future release. See [ROADMAP.md](./ROADMAP.md).
|
|
480
|
+
|
|
481
|
+
**Q: Can I use a different CSS framework?**
|
|
482
|
+
A: The templates are designed around Tailwind CSS 4. Swapping it out is possible but requires manual work. Additional styling options are on the roadmap.
|
|
483
|
+
|
|
484
|
+
**Q: The CLI overwrote my directory, can I undo it?**
|
|
485
|
+
A: The CLI asks for confirmation before overwriting. If you confirmed by mistake, restore from git or a backup — the CLI does not keep a copy.
|
|
486
|
+
|
|
487
|
+
**Q: How do I update to a newer template version?**
|
|
488
|
+
A: Re-run the scaffold into a new directory and manually migrate your custom code. There is no in-place upgrade mechanism currently.
|
|
489
|
+
|
|
490
|
+
**Q: Why does `npm run dev` use Turbopack in Web but not in Admin?**
|
|
491
|
+
A: The Web template targets higher-complexity landing pages where faster rebuilds matter most. The Admin template uses the standard Next.js dev server for broader compatibility. You can enable Turbopack in Admin by changing the `dev` script to `next dev --turbopack`.
|
|
492
|
+
|
|
493
|
+
**Q: Can I deploy the Full Stack template as a monorepo on Vercel?**
|
|
494
|
+
A: Yes — create two separate Vercel projects pointing to the same repository, and set their **Root Directory** to `web` and `admin` respectively.
|
|
495
|
+
|
|
496
|
+
---
|
|
497
|
+
|
|
498
|
+
## 🤝 Contributing
|
|
499
|
+
|
|
500
|
+
Contributions, bug reports, and feature requests are welcome!
|
|
501
|
+
|
|
502
|
+
1. [Open an issue](https://github.com/mburakaltiparmak/create-nextjs-stack/issues) to discuss what you'd like to change.
|
|
503
|
+
2. Fork the repository and create a feature branch:
|
|
504
|
+
|
|
505
|
+
```bash
|
|
506
|
+
git clone https://github.com/mburakaltiparmak/create-nextjs-stack.git
|
|
507
|
+
cd create-nextjs-stack
|
|
508
|
+
npm install
|
|
509
|
+
```
|
|
510
|
+
|
|
511
|
+
3. Make your changes, run the tests:
|
|
512
|
+
|
|
513
|
+
```bash
|
|
514
|
+
npm test
|
|
515
|
+
```
|
|
516
|
+
|
|
517
|
+
4. Submit a pull request with a clear description of the change.
|
|
518
|
+
|
|
519
|
+
Please follow [Conventional Commits](https://www.conventionalcommits.org/) for commit messages (`feat:`, `fix:`, `docs:`, `chore:`).
|
|
520
|
+
|
|
521
|
+
---
|
|
522
|
+
|
|
523
|
+
## 📋 Changelog
|
|
524
|
+
|
|
525
|
+
See [CHANGELOG.md](./CHANGELOG.md) for a full history of changes.
|
|
526
|
+
|
|
527
|
+
---
|
|
528
|
+
|
|
58
529
|
## 📝 License
|
|
59
530
|
|
|
60
|
-
MIT
|
|
531
|
+
[MIT](./LICENSE) © [Mehmet Burak Altıparmak](https://github.com/mburakaltiparmak)
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "create-nextjs-stack",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.4",
|
|
4
4
|
"description": "CLI to scaffold Next.js Landing Page and Supabase Admin Panel",
|
|
5
5
|
"private": false,
|
|
6
6
|
"bin": "./bin/cli.js",
|
|
@@ -40,9 +40,14 @@
|
|
|
40
40
|
"url": "https://github.com/mburakaltiparmak/create-nextjs-stack/issues"
|
|
41
41
|
},
|
|
42
42
|
"devDependencies": {
|
|
43
|
+
"@reduxjs/toolkit": "^2.11.2",
|
|
43
44
|
"@types/fs-extra": "^11.0.4",
|
|
44
45
|
"@types/node": "^25.2.3",
|
|
46
|
+
"@types/redux-logger": "^3.0.13",
|
|
45
47
|
"execa": "^9.6.1",
|
|
48
|
+
"react": "^19.2.4",
|
|
49
|
+
"react-redux": "^9.2.0",
|
|
50
|
+
"redux-logger": "^3.0.6",
|
|
46
51
|
"vitest": "^4.0.18"
|
|
47
52
|
}
|
|
48
53
|
}
|
|
@@ -4,14 +4,15 @@ import { getServerClient } from "@/lib/supabase/server";
|
|
|
4
4
|
import ResourceFormClient from "@/components/admin/ResourceFormClient";
|
|
5
5
|
|
|
6
6
|
interface PageProps {
|
|
7
|
-
params: {
|
|
7
|
+
params: Promise<{
|
|
8
8
|
resource: string;
|
|
9
9
|
id: string;
|
|
10
|
-
}
|
|
10
|
+
}>;
|
|
11
11
|
}
|
|
12
12
|
|
|
13
13
|
export default async function EditResourcePage({ params }: PageProps) {
|
|
14
|
-
const
|
|
14
|
+
const resolvedParams = await params;
|
|
15
|
+
const resourceName = resolvedParams.resource;
|
|
15
16
|
const config = resources.find((r) => r.name === resourceName);
|
|
16
17
|
|
|
17
18
|
if (!config) {
|
|
@@ -22,7 +23,7 @@ export default async function EditResourcePage({ params }: PageProps) {
|
|
|
22
23
|
const { data: item, error } = await supabase
|
|
23
24
|
.from(config.table)
|
|
24
25
|
.select("*")
|
|
25
|
-
.eq("id",
|
|
26
|
+
.eq("id", resolvedParams.id)
|
|
26
27
|
.single();
|
|
27
28
|
|
|
28
29
|
if (error || !item) {
|
|
@@ -38,7 +39,7 @@ export default async function EditResourcePage({ params }: PageProps) {
|
|
|
38
39
|
config={config}
|
|
39
40
|
mode="update"
|
|
40
41
|
initialData={item}
|
|
41
|
-
id={
|
|
42
|
+
id={resolvedParams.id}
|
|
42
43
|
/>
|
|
43
44
|
</div>
|
|
44
45
|
);
|
|
@@ -1,17 +1,16 @@
|
|
|
1
1
|
import { resources } from "@/config/resources";
|
|
2
|
-
import { notFound
|
|
3
|
-
import
|
|
4
|
-
import { createResource } from "@/app/actions/resources"; // We will create this
|
|
5
|
-
import ResourceFormClient from "@/components/admin/ResourceFormClient"; // Wrapper for logic
|
|
2
|
+
import { notFound } from "next/navigation";
|
|
3
|
+
import ResourceFormClient from "@/components/admin/ResourceFormClient";
|
|
6
4
|
|
|
7
5
|
interface PageProps {
|
|
8
|
-
params: {
|
|
6
|
+
params: Promise<{
|
|
9
7
|
resource: string;
|
|
10
|
-
}
|
|
8
|
+
}>;
|
|
11
9
|
}
|
|
12
10
|
|
|
13
|
-
export default function CreateResourcePage({ params }: PageProps) {
|
|
14
|
-
const
|
|
11
|
+
export default async function CreateResourcePage({ params }: PageProps) {
|
|
12
|
+
const resolvedParams = await params;
|
|
13
|
+
const resourceName = resolvedParams.resource;
|
|
15
14
|
const config = resources.find((r) => r.name === resourceName);
|
|
16
15
|
|
|
17
16
|
if (!config) {
|
|
@@ -20,13 +19,13 @@ export default function CreateResourcePage({ params }: PageProps) {
|
|
|
20
19
|
|
|
21
20
|
return (
|
|
22
21
|
<div>
|
|
23
|
-
|
|
22
|
+
<div className="mb-6">
|
|
24
23
|
<h1 className="text-2xl font-bold">Create {config.singular}</h1>
|
|
25
24
|
</div>
|
|
26
|
-
<ResourceFormClient
|
|
27
|
-
config={config}
|
|
25
|
+
<ResourceFormClient
|
|
26
|
+
config={config}
|
|
28
27
|
mode="create"
|
|
29
28
|
/>
|
|
30
29
|
</div>
|
|
31
30
|
);
|
|
32
|
-
}
|
|
31
|
+
}
|
|
@@ -6,13 +6,14 @@ import Image from "next/image";
|
|
|
6
6
|
import { getService } from "@/lib/services";
|
|
7
7
|
|
|
8
8
|
interface PageProps {
|
|
9
|
-
params: {
|
|
9
|
+
params: Promise<{
|
|
10
10
|
resource: string;
|
|
11
|
-
}
|
|
11
|
+
}>;
|
|
12
12
|
}
|
|
13
13
|
|
|
14
14
|
export default async function ResourceListPage({ params }: PageProps) {
|
|
15
|
-
const
|
|
15
|
+
const resolvedParams = await params;
|
|
16
|
+
const resourceName = resolvedParams.resource;
|
|
16
17
|
const config = resources.find((r) => r.name === resourceName);
|
|
17
18
|
|
|
18
19
|
if (!config) {
|