@amirulabu/create-recurring-rabbit-app 0.0.0-alpha

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.
Files changed (64) hide show
  1. package/bin/index.js +2 -0
  2. package/dist/index.js +592 -0
  3. package/package.json +43 -0
  4. package/templates/default/.editorconfig +21 -0
  5. package/templates/default/.env.example +15 -0
  6. package/templates/default/.eslintrc.json +35 -0
  7. package/templates/default/.prettierrc.json +7 -0
  8. package/templates/default/README.md +346 -0
  9. package/templates/default/app.config.ts +20 -0
  10. package/templates/default/docs/adding-features.md +439 -0
  11. package/templates/default/docs/adr/001-use-sqlite-for-development-database.md +22 -0
  12. package/templates/default/docs/adr/002-use-tanstack-start-over-nextjs.md +22 -0
  13. package/templates/default/docs/adr/003-use-better-auth-over-nextauth.md +22 -0
  14. package/templates/default/docs/adr/004-use-drizzle-over-prisma.md +22 -0
  15. package/templates/default/docs/adr/005-use-trpc-for-api-layer.md +22 -0
  16. package/templates/default/docs/adr/006-use-tailwind-css-v4-with-shadcn-ui.md +22 -0
  17. package/templates/default/docs/architecture.md +241 -0
  18. package/templates/default/docs/database.md +376 -0
  19. package/templates/default/docs/deployment.md +435 -0
  20. package/templates/default/docs/troubleshooting.md +668 -0
  21. package/templates/default/drizzle/migrations/0001_initial_schema.sql +39 -0
  22. package/templates/default/drizzle/migrations/meta/0001_snapshot.json +225 -0
  23. package/templates/default/drizzle/migrations/meta/_journal.json +12 -0
  24. package/templates/default/drizzle.config.ts +10 -0
  25. package/templates/default/lighthouserc.json +78 -0
  26. package/templates/default/src/app/__root.tsx +32 -0
  27. package/templates/default/src/app/api/auth/$.ts +15 -0
  28. package/templates/default/src/app/api/trpc.server.ts +12 -0
  29. package/templates/default/src/app/auth/forgot-password.tsx +107 -0
  30. package/templates/default/src/app/auth/login.tsx +34 -0
  31. package/templates/default/src/app/auth/register.tsx +34 -0
  32. package/templates/default/src/app/auth/reset-password.tsx +171 -0
  33. package/templates/default/src/app/auth/verify-email.tsx +111 -0
  34. package/templates/default/src/app/dashboard/index.tsx +122 -0
  35. package/templates/default/src/app/dashboard/settings.tsx +161 -0
  36. package/templates/default/src/app/globals.css +55 -0
  37. package/templates/default/src/app/index.tsx +83 -0
  38. package/templates/default/src/components/features/auth/login-form.tsx +172 -0
  39. package/templates/default/src/components/features/auth/register-form.tsx +202 -0
  40. package/templates/default/src/components/layout/dashboard-layout.tsx +27 -0
  41. package/templates/default/src/components/layout/header.tsx +29 -0
  42. package/templates/default/src/components/layout/sidebar.tsx +38 -0
  43. package/templates/default/src/components/ui/button.tsx +57 -0
  44. package/templates/default/src/components/ui/card.tsx +79 -0
  45. package/templates/default/src/components/ui/input.tsx +24 -0
  46. package/templates/default/src/lib/api.ts +42 -0
  47. package/templates/default/src/lib/auth.ts +292 -0
  48. package/templates/default/src/lib/email.ts +221 -0
  49. package/templates/default/src/lib/env.ts +119 -0
  50. package/templates/default/src/lib/hydration-timing.ts +289 -0
  51. package/templates/default/src/lib/monitoring.ts +336 -0
  52. package/templates/default/src/lib/utils.ts +6 -0
  53. package/templates/default/src/server/api/root.ts +10 -0
  54. package/templates/default/src/server/api/routers/dashboard.ts +37 -0
  55. package/templates/default/src/server/api/routers/user.ts +31 -0
  56. package/templates/default/src/server/api/trpc.ts +132 -0
  57. package/templates/default/src/server/auth/config.ts +241 -0
  58. package/templates/default/src/server/db/index.ts +153 -0
  59. package/templates/default/src/server/db/migrate.ts +125 -0
  60. package/templates/default/src/server/db/schema.ts +170 -0
  61. package/templates/default/src/server/db/seed.ts +130 -0
  62. package/templates/default/src/types/global.d.ts +25 -0
  63. package/templates/default/tailwind.config.js +46 -0
  64. package/templates/default/tsconfig.json +36 -0
@@ -0,0 +1,35 @@
1
+ {
2
+ "$schema": "https://json.schemastore.org/eslintrc",
3
+ "extends": [
4
+ "eslint:recommended",
5
+ "plugin:@typescript-eslint/recommended",
6
+ "plugin:react/recommended",
7
+ "plugin:react-hooks/recommended"
8
+ ],
9
+ "plugins": ["@typescript-eslint", "react", "react-hooks"],
10
+ "parser": "@typescript-eslint/parser",
11
+ "parserOptions": {
12
+ "ecmaVersion": "latest",
13
+ "sourceType": "module",
14
+ "ecmaFeatures": {
15
+ "jsx": true
16
+ }
17
+ },
18
+ "settings": {
19
+ "react": {
20
+ "version": "detect"
21
+ }
22
+ },
23
+ "rules": {
24
+ "@typescript-eslint/no-unused-vars": [
25
+ "error",
26
+ {
27
+ "argsIgnorePattern": "^_"
28
+ }
29
+ ],
30
+ "@typescript-eslint/no-explicit-any": "error",
31
+ "react/react-in-jsx-scope": "error",
32
+ "react-hooks/rules-of-hooks": "error",
33
+ "react-hooks/exhaustive-deps": "warn"
34
+ }
35
+ }
@@ -0,0 +1,7 @@
1
+ {
2
+ "semi": false,
3
+ "trailingComma": "es5",
4
+ "singleQuote": true,
5
+ "tabWidth": 2,
6
+ "useTabs": false
7
+ }
@@ -0,0 +1,346 @@
1
+ # Recurring Rabbit
2
+
3
+ > A production-ready micro-SaaS starter built with TanStack Start, tRPC, Drizzle, Better-auth, and Tailwind CSS.
4
+
5
+ ## Quick Start
6
+
7
+ ```bash
8
+ # Install dependencies
9
+ npm install
10
+
11
+ # Start development server
12
+ npm run dev
13
+
14
+ # Open http://localhost:3000 and create an account
15
+ ```
16
+
17
+ ## What's Included
18
+
19
+ - 🔐 **Authentication** - Email/password with verification via Better-auth
20
+ - 🗄️ **Database** - SQLite (dev) / Postgres (prod) with Drizzle ORM
21
+ - 🌐 **Full-stack** - TanStack Start with tRPC for type-safe APIs
22
+ - 🎨 **Styling** - Tailwind CSS with shadcn/ui components
23
+ - ⚡ **TypeScript** - End-to-end type safety
24
+ - 🔧 **Developer Tools** - Hot reload, ESLint, Prettier, VS Code config
25
+
26
+ ## Project Structure
27
+
28
+ ```
29
+ src/
30
+ ├── app/ # TanStack Start routes
31
+ ├── server/ # tRPC API and database
32
+ ├── components/ # Reusable UI components
33
+ └── lib/ # Shared utilities
34
+ ```
35
+
36
+ ## Key Commands
37
+
38
+ ```bash
39
+ # Development
40
+ npm run dev # Start development server
41
+ npm run build # Build for production
42
+ npm run start # Start production server
43
+
44
+ # Bundle Analysis
45
+ npm run build:analyze # Build with bundle analyzer (opens stats.html)
46
+
47
+ # Database
48
+ npm run db:generate # Generate migration files
49
+ npm run db:migrate # Apply migrations
50
+ npm run db:studio # Open Drizzle Studio
51
+ npm run db:seed # Seed database with sample data
52
+
53
+ # Code Quality
54
+ npm run typecheck # Run TypeScript checks
55
+ npm run lint # Run ESLint
56
+ npm run lint:fix # Fix ESLint issues
57
+ npm run format # Format code with Prettier
58
+ npm run clean # Clean build artifacts
59
+ ```
60
+
61
+ ## Environment Setup
62
+
63
+ Copy `.env.example` to `.env.local` and customize:
64
+
65
+ ```bash
66
+ cp .env.example .env.local
67
+ ```
68
+
69
+ Required variables:
70
+
71
+ - `BETTER_AUTH_SECRET` - Random 32+ character string (auto-generated during setup)
72
+ - `RESEND_API_KEY` - For email verification (get from [Resend](https://resend.com))
73
+
74
+ Optional variables (production):
75
+
76
+ - `DATABASE_URL` - PostgreSQL connection string
77
+ - `BETTER_AUTH_URL` - Your production domain (https://yourdomain.com)
78
+ - `PUBLIC_APP_URL` - Same as BETTER_AUTH_URL
79
+
80
+ ## Development
81
+
82
+ ### Bundle Analysis
83
+
84
+ Analyze your bundle size to identify large dependencies and optimize performance:
85
+
86
+ ```bash
87
+ npm run build:analyze
88
+ ```
89
+
90
+ This will build your application and generate a `stats.html` file in build output directory (`.vinxi`). Open this file in your browser to explore:
91
+
92
+ - **Treemap view** - Visual representation of module sizes
93
+ - **Gzip/Brotli sizes** - Real-world compression impact
94
+ - **Module hierarchy** - See which modules depend on what
95
+
96
+ **Tips for optimization:**
97
+
98
+ - Look for large dependencies that could be tree-shaken
99
+ - Identify duplicate code that can be deduplicated
100
+ - Check if route-based code splitting is working
101
+ - Remove unused dependencies when possible
102
+
103
+ ### Performance Monitoring
104
+
105
+ Monitor application performance to identify bottlenecks:
106
+
107
+ ```bash
108
+ # Run Lighthouse CI to check performance budgets
109
+ npm run lighthouse
110
+ ```
111
+
112
+ The project includes performance monitoring tools:
113
+
114
+ **Slow Query Logging** (Development):
115
+
116
+ - Database queries over 1 second are logged to console
117
+ - Helps identify database performance issues
118
+ - Enabled automatically in development mode
119
+
120
+ **Client Hydration Timing** (Development):
121
+
122
+ - Track component hydration time
123
+ - Components taking over 100ms to hydrate trigger warnings
124
+ - Use `markHydrationStart()` and `markHydrationEnd()` in components
125
+
126
+ **Performance Budgets** (Lighthouse CI):
127
+
128
+ - First Contentful Paint: < 2000ms
129
+ - Largest Contentful Paint: < 2500ms
130
+ - Time to Interactive: < 3500ms
131
+ - JavaScript bundles: < 150KB
132
+ - Total page size: < 500KB
133
+
134
+ **Using Monitoring in Code:**
135
+
136
+ ```typescript
137
+ // Track database queries
138
+ import { measureQuery } from '@/lib/monitoring'
139
+
140
+ const result = await measureQuery('SELECT * FROM users', () => {
141
+ return db.query(users.findMany())
142
+ })
143
+
144
+ // Track hydration
145
+ import { markHydrationStart, markHydrationEnd } from '@/lib/hydration-timing'
146
+
147
+ export function MyComponent() {
148
+ markHydrationStart('MyComponent')
149
+
150
+ useEffect(() => {
151
+ markHydrationEnd('MyComponent')
152
+ }, [])
153
+
154
+ return <div>...</div>
155
+ }
156
+ ```
157
+
158
+ ### Adding New Features
159
+
160
+ **Database Tables**
161
+
162
+ 1. Define schema in `src/server/db/schema.ts`
163
+ 2. Generate migration: `npm run db:generate`
164
+ 3. Apply migration: `npm run db:migrate`
165
+
166
+ ```typescript
167
+ export const posts = sqliteTable('posts', {
168
+ id: text('id')
169
+ .primaryKey()
170
+ .$defaultFn(() => createId()),
171
+ title: text('title').notNull(),
172
+ content: text('content').notNull(),
173
+ userId: text('user_id').references(() => users.id, { onDelete: 'cascade' }),
174
+ createdAt: integer('created_at', { mode: 'timestamp' }).$defaultFn(
175
+ () => new Date()
176
+ ),
177
+ })
178
+ ```
179
+
180
+ **tRPC Procedures**
181
+
182
+ 1. Create router in `src/server/api/[feature].ts`
183
+ 2. Add to root router in `src/server/api/root.ts`
184
+ 3. Use in components via `api.[feature].[procedure].useQuery()`
185
+
186
+ ```typescript
187
+ export const postsRouter = router({
188
+ create: protectedProcedure
189
+ .input(z.object({ title: z.string(), content: z.string() }))
190
+ .mutation(async ({ ctx, input }) => {
191
+ return await ctx.db
192
+ .insert(posts)
193
+ .values({
194
+ ...input,
195
+ userId: ctx.user.id,
196
+ })
197
+ .returning()
198
+ }),
199
+ })
200
+ ```
201
+
202
+ **New Pages**
203
+
204
+ 1. Add route file in `src/app/[route].tsx`
205
+ 2. Implement component with TanStack Start conventions
206
+ 3. Add navigation in layout components
207
+
208
+ **Protected Pages**
209
+
210
+ ```typescript
211
+ export const Route = createFileRoute('/dashboard')({
212
+ beforeLoad: ({ context }) => {
213
+ if (!context.auth.user) {
214
+ throw redirect({ to: '/auth/login' })
215
+ }
216
+ },
217
+ component: Dashboard,
218
+ })
219
+ ```
220
+
221
+ ### Adding UI Components
222
+
223
+ 1. Install shadcn component: `npx shadcn-ui add [component]`
224
+ 2. Customize styling in component file or CSS variables
225
+ 3. Create feature-specific components in `src/components/features/`
226
+
227
+ ## Deployment
228
+
229
+ ### Vercel (Recommended)
230
+
231
+ ```bash
232
+ vercel deploy
233
+ ```
234
+
235
+ Set environment variables in Vercel dashboard and add production PostgreSQL database.
236
+
237
+ ### Railway
238
+
239
+ ```bash
240
+ railway up
241
+ ```
242
+
243
+ Railway provides built-in PostgreSQL hosting.
244
+
245
+ ### Environment Variables for Production
246
+
247
+ - `BETTER_AUTH_SECRET` - New random 32+ character string
248
+ - `DATABASE_URL` - Production PostgreSQL connection string
249
+ - `BETTER_AUTH_URL` - Your production domain (https://yourdomain.com)
250
+ - `PUBLIC_APP_URL` - Same as BETTER_AUTH_URL
251
+ - `RESEND_API_KEY` - Production API key from Resend
252
+
253
+ ### Database Migrations in Production
254
+
255
+ When deploying to production with PostgreSQL:
256
+
257
+ ```bash
258
+ npm run db:migrate
259
+ ```
260
+
261
+ Make sure to test migrations locally with PostgreSQL before deploying.
262
+
263
+ ## Database Schema
264
+
265
+ The database includes the following tables:
266
+
267
+ - **users** - User accounts with email verification
268
+ - **sessions** - Active user sessions
269
+ - **accounts** - OAuth provider accounts (for future use)
270
+ - **verifications** - Email verification and password reset tokens
271
+
272
+ View and edit the schema in `src/server/db/schema.ts`.
273
+
274
+ ## Authentication Flow
275
+
276
+ 1. User registers with email/password
277
+ 2. Email verification required before dashboard access
278
+ 3. Sessions stored in database with automatic cleanup
279
+ 4. CSRF protection enabled on all authenticated routes
280
+ 5. Password reset flow available (requires Resend setup)
281
+
282
+ ## Troubleshooting
283
+
284
+ ### pnpm Native Module Build Issues
285
+
286
+ pnpm blocks build scripts for native modules by default. If you encounter better-sqlite3 issues:
287
+
288
+ ```bash
289
+ pnpm rebuild better-sqlite3
290
+ ```
291
+
292
+ Or use npm/yarn instead of pnpm.
293
+
294
+ ### Drizzle-kit Migrate with SQLite
295
+
296
+ Use `drizzle-kit push` instead of `drizzle-kit migrate` for SQLite to avoid multi-statement SQL issues.
297
+
298
+ ### Email Not Sending
299
+
300
+ 1. Verify RESEND_API_KEY is set in `.env.local`
301
+ 2. Check Resend dashboard for API key status
302
+ 3. Verify email domain is verified in Resend
303
+ 4. Configure SPF/DKIM records for email deliverability
304
+
305
+ ### Database Locked (SQLite)
306
+
307
+ If you get "database is locked" errors:
308
+
309
+ ```bash
310
+ npm run clean
311
+ # Then restart dev server
312
+ ```
313
+
314
+ This removes SQLite WAL files that can cause locking issues.
315
+
316
+ ## Documentation
317
+
318
+ - [Architecture Overview](docs/architecture.md) - System design and key decisions
319
+ - [Adding Features](docs/adding-features.md) - Common patterns and examples
320
+ - [Deployment Guide](docs/deployment.md) - Platform-specific deployment instructions
321
+ - [Database Schema](docs/database.md) - Complete schema documentation
322
+ - [Troubleshooting](docs/troubleshooting.md) - Common issues and solutions
323
+
324
+ ## Architecture Decisions
325
+
326
+ ### Why TanStack Start over Next.js?
327
+
328
+ - Better TypeScript integration with less configuration
329
+ - File-based routing without App Router complexity
330
+ - Smaller bundle size for micro-SaaS use cases
331
+
332
+ ### Why Better-auth over NextAuth?
333
+
334
+ - Simpler configuration for basic email/password auth
335
+ - Better TypeScript support with fewer generic type issues
336
+ - Database session storage built-in for scalability
337
+
338
+ ### Why Drizzle over Prisma?
339
+
340
+ - Zero runtime overhead with compile-time query building
341
+ - Better migration control with SQL-first approach
342
+ - Lighter weight for simple SaaS data models
343
+
344
+ ## License
345
+
346
+ MIT - See LICENSE file for details.
@@ -0,0 +1,20 @@
1
+ import { defineConfig } from '@tanstack/start/config'
2
+ import { visualizer } from 'rollup-plugin-visualizer'
3
+
4
+ export default defineConfig({
5
+ tsr: {
6
+ appDirectory: 'src/app',
7
+ routesDirectory: 'src/app',
8
+ },
9
+ vite: {
10
+ plugins: [
11
+ visualizer({
12
+ filename: 'stats.html',
13
+ open: process.env.ANALYZE_BUNDLE === 'true',
14
+ gzipSize: true,
15
+ brotliSize: true,
16
+ template: 'treemap',
17
+ }),
18
+ ],
19
+ },
20
+ })