create-fullstack-scaffold 0.4.23 → 0.4.25
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 +231 -104
- package/dist/cli/index.js +7 -0
- package/dist/cli/index.js.map +1 -1
- package/package.json +1 -1
- package/template/package.json +1 -0
- package/template/src/admin/i18n/locales/en-US.json +10 -1
- package/template/src/admin/i18n/locales/zh-CN.json +10 -1
- package/template/src/admin/pages/SettingsPage.tsx +96 -47
- package/template/src/server/module-admin/routes/system-routes.ts +53 -0
- package/template/src/server/module-auth/__tests__/profile-routes.test.ts +27 -17
- package/template/src/shared/modules/admin/schemas.ts +16 -0
- package/template/vite.config.ts +26 -1
- package/template/drizzle/0000_rainy_boomer.sql +0 -101
- package/template/drizzle/0001_add_todo_attachments.sql +0 -12
- package/template/drizzle/0002_chilly_magneto.sql +0 -89
- package/template/drizzle/0003_ambiguous_magdalene.sql +0 -100
- package/template/drizzle/0004_add_merchants_products.sql +0 -30
- package/template/drizzle/meta/0000_snapshot.json +0 -652
- package/template/drizzle/meta/0001_snapshot.json +0 -735
- package/template/drizzle/meta/0002_snapshot.json +0 -1198
- package/template/drizzle/meta/0003_snapshot.json +0 -1837
- package/template/drizzle/meta/_journal.json +0 -41
- package/template/pnpm-lock.yaml +0 -7137
package/README.md
CHANGED
|
@@ -1,154 +1,281 @@
|
|
|
1
|
-
# create-
|
|
1
|
+
# create-fullstack-scaffold
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
[](https://www.npmjs.com/package/create-fullstack-scaffold)
|
|
4
4
|
|
|
5
|
-
|
|
5
|
+
Zero-config fullstack app generator with type-safe RPC, 15+ modules, and 8 production-ready presets. One command, zero `.env`, instant `npm run dev`.
|
|
6
6
|
|
|
7
|
-
|
|
8
|
-
- **Backend**: Hono with TypeScript
|
|
9
|
-
- **Database**: SQLite with Drizzle ORM
|
|
10
|
-
- **State Management**: Zustand
|
|
11
|
-
- **Real-time**: WebSocket + SSE support
|
|
12
|
-
- **Testing**: Vitest (unit + integration tests)
|
|
13
|
-
- **Code Quality**: ESLint, Prettier, pre-commit hooks
|
|
14
|
-
- **Type Safety**: End-to-end type safety with Hono RPC
|
|
7
|
+
## Quick Start
|
|
15
8
|
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
src/
|
|
20
|
-
├── client/ # React frontend
|
|
21
|
-
│ ├── components/ # UI components
|
|
22
|
-
│ ├── stores/ # Zustand state management
|
|
23
|
-
│ ├── services/ # API clients (apiClient)
|
|
24
|
-
│ ├── hooks/ # Custom hooks
|
|
25
|
-
│ ├── pages/ # Page components
|
|
26
|
-
│ └── App.tsx
|
|
27
|
-
├── server/ # Hono backend
|
|
28
|
-
│ ├── module-todos/ # Todo module
|
|
29
|
-
│ ├── module-chat/ # WebSocket chat module
|
|
30
|
-
│ ├── module-notifications/ # SSE notifications module
|
|
31
|
-
│ ├── core/ # Core services (runtime, realtime)
|
|
32
|
-
│ ├── middleware/ # Express middleware
|
|
33
|
-
│ ├── test-utils/ # Test utilities
|
|
34
|
-
│ └── entries/ # Entry points (node.ts, cloudflare.ts)
|
|
35
|
-
└── shared/ # Shared types
|
|
36
|
-
├── core/ # Framework layer (ws-client, sse-client)
|
|
37
|
-
├── modules/ # Business layer (chat, todos, notifications)
|
|
38
|
-
└── schemas/ # Unified exports
|
|
9
|
+
```bash
|
|
10
|
+
npx create-fullstack-scaffold@latest my-app
|
|
11
|
+
cd my-app && npm install && npm run dev
|
|
39
12
|
```
|
|
40
13
|
|
|
41
|
-
|
|
14
|
+
Open http://localhost:3010 — that's it. No `.env` required.
|
|
42
15
|
|
|
43
|
-
|
|
16
|
+
## Tech Stack
|
|
44
17
|
|
|
45
|
-
|
|
46
|
-
npm install
|
|
47
|
-
```
|
|
18
|
+
React + Hono + Vite + Zustand + TypeScript + Ant Design + Zod
|
|
48
19
|
|
|
49
|
-
|
|
20
|
+
| Layer | Technology | Purpose |
|
|
21
|
+
| ---------- | -------------------- | ----------------------------------- |
|
|
22
|
+
| Frontend | React 19 + Vite | Client SPA with HMR |
|
|
23
|
+
| Admin | Ant Design 5 | Admin/merchant/tenant dashboards |
|
|
24
|
+
| Backend | Hono (OpenAPI) | Type-safe RPC server |
|
|
25
|
+
| State | Zustand | Client-side state management |
|
|
26
|
+
| Validation | Zod | Shared schemas, end-to-end |
|
|
27
|
+
| DB | Drizzle ORM + SQLite | Pluggable data layer |
|
|
28
|
+
| Realtime | WebSocket + SSE | Built-in typed protocols |
|
|
29
|
+
| CLI | Commander | `biomimic` CLI for agent automation |
|
|
50
30
|
|
|
51
|
-
|
|
52
|
-
npm run dev
|
|
53
|
-
```
|
|
31
|
+
## Presets
|
|
54
32
|
|
|
55
|
-
|
|
33
|
+
8 presets. Each generates a different app by including/excluding modules.
|
|
56
34
|
|
|
57
|
-
|
|
35
|
+
| Preset | Modules | Use Case |
|
|
36
|
+
| ---------------------- | ---------------------------------------------------------------------------------------------------------------------------------- | ---------------------------- |
|
|
37
|
+
| `fullstack-admin` | todos, chat, notifications, file, captcha, permission, admin, auth, plugin, tenant, order, ticket, dispute, content, merchant (15) | Full-featured admin platform |
|
|
38
|
+
| `todo-app` | todos, chat, notifications, auth (4) | Learning / simple app |
|
|
39
|
+
| `ecommerce` | todos, chat, notifications, file, permission, order, ticket, dispute, content (9) | E-commerce store |
|
|
40
|
+
| `xbrowser-marketplace` | notifications, file, captcha, auth, permission, admin, plugin, order, ticket, dispute, content (11) | Plugin marketplace |
|
|
41
|
+
| `forum` | content, auth, permission, admin, notifications (5) | Community forum |
|
|
42
|
+
| `cli-only` | todos, chat, notifications, auth (4) | CLI agent / no browser UI |
|
|
43
|
+
| `minimal` | todos (1) | Bare minimum starting point |
|
|
44
|
+
| `saas` | todos, notifications, file, captcha, permission, auth, tenant, content (8) | Multi-tenant SaaS |
|
|
58
45
|
|
|
59
46
|
```bash
|
|
60
|
-
|
|
47
|
+
# Choose a preset
|
|
48
|
+
npx create-fullstack-scaffold@latest my-app --preset ecommerce
|
|
61
49
|
```
|
|
62
50
|
|
|
63
|
-
|
|
51
|
+
## Type-Safe RPC
|
|
64
52
|
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
53
|
+
Every API call is fully typed — zero code generation, powered by Hono RPC.
|
|
54
|
+
|
|
55
|
+
```typescript
|
|
56
|
+
import { apiClient } from '@client/services/apiClient'
|
|
57
|
+
|
|
58
|
+
// HTTP — typed request + response
|
|
59
|
+
const res = await apiClient.api.todos.$get()
|
|
60
|
+
const { data } = await res.json() // data: Todo[]
|
|
68
61
|
|
|
69
|
-
|
|
70
|
-
|
|
62
|
+
// WebSocket — typed RPC + events
|
|
63
|
+
const ws = apiClient.api.chat.ws.$ws()
|
|
64
|
+
const result = await ws.call('echo', { message: 'hello' })
|
|
71
65
|
|
|
72
|
-
|
|
73
|
-
|
|
66
|
+
// SSE — typed server-push
|
|
67
|
+
const conn = await apiClient.api.notifications.stream.$sse()
|
|
68
|
+
conn.on('notification', n => console.log(n.title))
|
|
69
|
+
|
|
70
|
+
// Media — typed binary responses
|
|
71
|
+
const blob = await apiClient.api.avatar[':id'].$image({ param: { id: '123' } })
|
|
72
|
+
const svg = await apiClient.api.icon[':name'].$svg({ param: { name: 'home' } })
|
|
73
|
+
const file = await apiClient.api.export.$download()
|
|
74
74
|
```
|
|
75
75
|
|
|
76
|
-
|
|
76
|
+
| Protocol | Method | Return Type |
|
|
77
|
+
| ------------- | ------------------------------------------ | --------------------- |
|
|
78
|
+
| HTTP JSON | `$get()`, `$post()`, `$put()`, `$delete()` | `ClientResponse<T>` |
|
|
79
|
+
| WebSocket | `$ws()` | `WSClient<Protocol>` |
|
|
80
|
+
| SSE | `$sse()` | `SSEClient<Protocol>` |
|
|
81
|
+
| Image | `$image()` | `Promise<Blob>` |
|
|
82
|
+
| SVG | `$svg()` | `Promise<string>` |
|
|
83
|
+
| File Download | `$download()` | `Promise<Blob>` |
|
|
77
84
|
|
|
78
|
-
|
|
85
|
+
## Architecture
|
|
79
86
|
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
87
|
+
```
|
|
88
|
+
┌─────────────────────────────────────────────────────────┐
|
|
89
|
+
│ Generated App │
|
|
90
|
+
│ │
|
|
91
|
+
│ ┌──────────┐ ┌──────────┐ ┌──────────┐ ┌─────────┐ │
|
|
92
|
+
│ │ Client │ │ Admin │ │ Tenant │ │Merchant │ │
|
|
93
|
+
│ │ (React) │ │(Ant Design)│ │(Ant Design)│ │(Ant Design)│
|
|
94
|
+
│ │ index.html│ │admin.html│ │tenant.html│ │merchant │ │
|
|
95
|
+
│ └─────┬─────┘ └────┬─────┘ └────┬─────┘ └────┬────┘ │
|
|
96
|
+
│ │ │ │ │ │
|
|
97
|
+
│ └──────────────┴──────────────┴──────────────┘ │
|
|
98
|
+
│ │ │
|
|
99
|
+
│ apiClient (hc) │
|
|
100
|
+
│ type-safe RPC │
|
|
101
|
+
│ │ │
|
|
102
|
+
│ ┌───────────────────────────┴───────────────────────────┐ │
|
|
103
|
+
│ │ Hono Server (Single Port) │ │
|
|
104
|
+
│ │ │ │
|
|
105
|
+
│ │ ┌─────────┐ ┌─────────┐ ┌─────────┐ ┌─────────────┐ │ │
|
|
106
|
+
│ │ │module- │ │module- │ │module- │ │module- │ │ │
|
|
107
|
+
│ │ │todos │ │chat │ │notifi- │ │admin │ │ │
|
|
108
|
+
│ │ │ │ │ │ │cations │ │ │ │ │
|
|
109
|
+
│ │ │routes/ │ │routes/ │ │routes/ │ │routes/ │ │ │
|
|
110
|
+
│ │ │services/│ │services/│ │services/│ │services/ │ │ │
|
|
111
|
+
│ │ │__tests__/│ │__tests__/│ │__tests__/│ │__tests__/ │ │ │
|
|
112
|
+
│ │ └─────────┘ └─────────┘ └─────────┘ └─────────────┘ │ │
|
|
113
|
+
│ │ + 11 more modules (order, ticket, dispute, ...) │ │
|
|
114
|
+
│ └───────────────────────────────────────────────────────┘ │
|
|
115
|
+
│ │ │
|
|
116
|
+
│ ┌────────┴────────┐ │
|
|
117
|
+
│ │ Shared / │ │
|
|
118
|
+
│ │ core/ (Zod) │ │
|
|
119
|
+
│ │ modules/ (types)│ │
|
|
120
|
+
│ └─────────────────┘ │
|
|
121
|
+
└─────────────────────────────────────────────────────────────┘
|
|
122
|
+
```
|
|
83
123
|
|
|
84
|
-
###
|
|
124
|
+
### Module System
|
|
85
125
|
|
|
86
|
-
|
|
126
|
+
15 modules with declarative manifests (`module.ts`). Each declares routes, dependencies, DB schemas, CLI commands, and pages.
|
|
87
127
|
|
|
88
|
-
|
|
128
|
+
| Category | Modules |
|
|
129
|
+
| ------------- | -------------------------------------------------------------------- |
|
|
130
|
+
| Core | `todos` |
|
|
131
|
+
| Communication | `chat`, `notifications` |
|
|
132
|
+
| System | `permission`, `admin`, `auth`, `captcha`, `file`, `tenant`, `plugin` |
|
|
133
|
+
| Business | `order`, `ticket`, `dispute`, `content`, `merchant` |
|
|
89
134
|
|
|
90
|
-
|
|
135
|
+
### Multi-Entry HTML
|
|
91
136
|
|
|
92
|
-
|
|
93
|
-
- **Business Layer** (`src/shared/modules/`): Business-specific schemas and protocols
|
|
137
|
+
Up to 4 independent SPAs, generated based on preset modules:
|
|
94
138
|
|
|
95
|
-
|
|
139
|
+
| Entry | File | Included When |
|
|
140
|
+
| -------- | --------------- | -------------------------------------- |
|
|
141
|
+
| Client | `index.html` | Always |
|
|
142
|
+
| Admin | `admin.html` | `admin` or `permission` module present |
|
|
143
|
+
| Tenant | `tenant.html` | `tenant` module present |
|
|
144
|
+
| Merchant | `merchant.html` | `merchant` module present |
|
|
96
145
|
|
|
97
|
-
|
|
146
|
+
Each entry has its own `App.tsx`, router, and layout — fully isolated.
|
|
98
147
|
|
|
99
|
-
|
|
100
|
-
import { apiClient } from '@client/services/apiClient'
|
|
148
|
+
### Module Dependency Graph
|
|
101
149
|
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
150
|
+
```
|
|
151
|
+
todos ──── (standalone)
|
|
152
|
+
chat ──── (standalone)
|
|
153
|
+
notifications ──── (standalone)
|
|
154
|
+
file ──── (standalone)
|
|
155
|
+
captcha ──── (standalone)
|
|
156
|
+
auth ──── (standalone)
|
|
157
|
+
permission ──── (standalone, foundational)
|
|
158
|
+
admin ────→ permission + notifications
|
|
159
|
+
plugin ────→ auth + permission + notifications
|
|
160
|
+
tenant ────→ auth + permission
|
|
161
|
+
order ────→ permission
|
|
162
|
+
ticket ────→ permission
|
|
163
|
+
dispute ────→ permission
|
|
164
|
+
content ────→ permission
|
|
165
|
+
merchant ────→ auth + permission
|
|
166
|
+
```
|
|
105
167
|
|
|
106
|
-
|
|
107
|
-
const ws = apiClient.api.chat.ws.$ws()
|
|
108
|
-
const result = await ws.call('echo', { message: 'hello' })
|
|
168
|
+
## Deployment
|
|
109
169
|
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
170
|
+
| Platform | Entry | Command |
|
|
171
|
+
| ---------------------- | ---------------------------------- | ------------------------------------------------------ |
|
|
172
|
+
| **Cloudflare Workers** | `src/server/entries/cloudflare.ts` | `wrangler deploy` |
|
|
173
|
+
| **Node.js** | `src/server/entries/node.ts` | `node dist/server/entries/node.js` |
|
|
174
|
+
| **shanbox** | Dockerfile included | `docker build -t app . && docker run -p 3010:3010 app` |
|
|
175
|
+
|
|
176
|
+
```bash
|
|
177
|
+
# Build for production
|
|
178
|
+
npm run build
|
|
179
|
+
|
|
180
|
+
# Preview production build
|
|
181
|
+
npm run preview
|
|
113
182
|
```
|
|
114
183
|
|
|
115
|
-
|
|
184
|
+
## Development
|
|
116
185
|
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
186
|
+
```bash
|
|
187
|
+
npm run dev # Start dev server on :3010 (no .env needed)
|
|
188
|
+
npm run build # Production build
|
|
189
|
+
npm run typecheck # TypeScript type check
|
|
190
|
+
npm run lint # ESLint
|
|
191
|
+
npm run test # Vitest (all tests)
|
|
192
|
+
npm run test:unit # Unit tests only
|
|
193
|
+
npm run test:integration # Integration tests only
|
|
194
|
+
npm run validate:modules # Validate module manifests
|
|
195
|
+
```
|
|
196
|
+
|
|
197
|
+
## Project Structure
|
|
122
198
|
|
|
123
|
-
|
|
199
|
+
```
|
|
200
|
+
template/src/
|
|
201
|
+
├── client/ # React SPA (index.html)
|
|
202
|
+
│ ├── components/ # UI components
|
|
203
|
+
│ ├── stores/ # Zustand state
|
|
204
|
+
│ ├── services/ # apiClient
|
|
205
|
+
│ ├── hooks/ # Custom hooks
|
|
206
|
+
│ └── pages/ # Page components
|
|
207
|
+
├── admin/ # Admin dashboard (admin.html, Ant Design)
|
|
208
|
+
│ ├── components/
|
|
209
|
+
│ ├── stores/
|
|
210
|
+
│ ├── layouts/
|
|
211
|
+
│ └── pages/
|
|
212
|
+
├── tenant/ # Tenant dashboard (tenant.html, Ant Design)
|
|
213
|
+
│ └── ...
|
|
214
|
+
├── merchant/ # Merchant dashboard (merchant.html, Ant Design)
|
|
215
|
+
│ └── ...
|
|
216
|
+
├── server/ # Hono backend
|
|
217
|
+
│ ├── module-{name}/ # Feature modules (15+)
|
|
218
|
+
│ │ ├── module.ts # Declarative manifest
|
|
219
|
+
│ │ ├── routes/ # API endpoints
|
|
220
|
+
│ │ ├── services/ # Business logic
|
|
221
|
+
│ │ └── __tests__/ # Module tests
|
|
222
|
+
│ ├── core/ # Runtime, realtime scanner
|
|
223
|
+
│ ├── middleware/ # Auth, CORS, logger, captcha
|
|
224
|
+
│ ├── db/ # Drizzle schema + migrations
|
|
225
|
+
│ ├── entries/ # node.ts, cloudflare.ts
|
|
226
|
+
│ └── test-utils/ # createTestClient, createTestServer
|
|
227
|
+
├── shared/ # Shared types (client + server)
|
|
228
|
+
│ ├── core/ # Framework: ws-client, sse-client, api-schemas
|
|
229
|
+
│ ├── modules/ # Business: todos, chat, notifications, ...
|
|
230
|
+
│ └── schemas/ # Unified re-exports
|
|
231
|
+
└── cli/ # CLI agent (biomimic command)
|
|
232
|
+
├── modules/ # todo, notification, config, ...
|
|
233
|
+
└── rpc/ # hc RPC client
|
|
234
|
+
```
|
|
124
235
|
|
|
125
|
-
|
|
236
|
+
### Path Aliases
|
|
126
237
|
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
238
|
+
| Alias | Resolves To |
|
|
239
|
+
| ----------- | -------------- |
|
|
240
|
+
| `@shared/*` | `src/shared/*` |
|
|
241
|
+
| `@client/*` | `src/client/*` |
|
|
242
|
+
| `@server/*` | `src/server/*` |
|
|
243
|
+
| `@admin/*` | `src/admin/*` |
|
|
130
244
|
|
|
131
|
-
|
|
245
|
+
## Testing
|
|
132
246
|
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
- `__tests__/` - Unit tests
|
|
247
|
+
```typescript
|
|
248
|
+
import { createTestClient } from '@server/test-utils/test-client'
|
|
136
249
|
|
|
137
|
-
|
|
250
|
+
const client = createTestClient() // No server needed for HTTP/SSE
|
|
138
251
|
|
|
139
|
-
|
|
252
|
+
const res = await client.api.todos.$get() // Fully typed
|
|
253
|
+
const { data } = await res.json()
|
|
254
|
+
```
|
|
140
255
|
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
256
|
+
| Test Type | Needs Server | Tool |
|
|
257
|
+
| --------- | ------------ | ---------------------------------------------- |
|
|
258
|
+
| HTTP API | No | `createTestClient()` |
|
|
259
|
+
| SSE | No | `$sse()` via `createTestClient()` |
|
|
260
|
+
| WebSocket | Yes | `createTestServer()` + `createTestClient(url)` |
|
|
261
|
+
| E2E | Yes | Playwright |
|
|
144
262
|
|
|
145
|
-
##
|
|
263
|
+
## Quality Gates
|
|
146
264
|
|
|
147
|
-
|
|
265
|
+
- **TypeScript strict mode** — no `any`, explicit return types
|
|
266
|
+
- **ESLint** — 17 custom rules (chain syntax, layer boundaries, no inline schemas, ...)
|
|
267
|
+
- **Pre-commit hooks** — typecheck + lint-staged + smart tests
|
|
268
|
+
- **Module validation** — `npm run validate:modules` checks manifests
|
|
269
|
+
- **Production verified** — all 7 client presets pass `typecheck` + `build`
|
|
148
270
|
|
|
149
271
|
## Documentation
|
|
150
272
|
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
273
|
+
| File | Content |
|
|
274
|
+
| -------------------- | ----------------------------------------- |
|
|
275
|
+
| `CLAUDE.md` | Development guidelines for AI agents |
|
|
276
|
+
| `.claude/rules/` | 20+ detailed development constraint files |
|
|
277
|
+
| `template/CLAUDE.md` | Template-specific development guide |
|
|
278
|
+
|
|
279
|
+
## License
|
|
280
|
+
|
|
281
|
+
MIT
|
package/dist/cli/index.js
CHANGED
|
@@ -2855,6 +2855,7 @@ function generateViteConfig(resolved, templateDir) {
|
|
|
2855
2855
|
entriesToRemove.push("merchant");
|
|
2856
2856
|
aliasesToRemove.push("@merchant");
|
|
2857
2857
|
}
|
|
2858
|
+
const hasAntdConsumer = resolved.modules.has("admin") || resolved.modules.has("tenant") || resolved.modules.has("merchant");
|
|
2858
2859
|
for (const name of entriesToRemove) {
|
|
2859
2860
|
const re = new RegExp(
|
|
2860
2861
|
`^\\s*${name}:\\s*path\\.resolve\\(__dirname,\\s*['"]${name}\\.html['"]\\),\\s*$\\n?`,
|
|
@@ -2871,6 +2872,12 @@ function generateViteConfig(resolved, templateDir) {
|
|
|
2871
2872
|
);
|
|
2872
2873
|
content = content.replace(re, "");
|
|
2873
2874
|
}
|
|
2875
|
+
if (!hasAntdConsumer) {
|
|
2876
|
+
const antdChunkRe = /^(\s*'vendor-antd':\s*\['antd',\s*'@ant-design\/icons'\],\s*\n)/gm;
|
|
2877
|
+
content = content.replace(antdChunkRe, "");
|
|
2878
|
+
const onwarnRe = /^\s*\/\/ Suppress antd "use client" directive warnings[^\n]*\n\s*if \(warning\.code === 'MODULE_LEVEL_DIRECTIVE'\) return\n/gm;
|
|
2879
|
+
content = content.replace(onwarnRe, "");
|
|
2880
|
+
}
|
|
2874
2881
|
return content;
|
|
2875
2882
|
}
|
|
2876
2883
|
|