red64-cli 0.1.0 → 0.2.0
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/dist/cli/parseArgs.d.ts.map +1 -1
- package/dist/cli/parseArgs.js +5 -0
- package/dist/cli/parseArgs.js.map +1 -1
- package/dist/components/init/CompleteStep.d.ts.map +1 -1
- package/dist/components/init/CompleteStep.js +2 -2
- package/dist/components/init/CompleteStep.js.map +1 -1
- package/dist/components/init/TestCheckStep.d.ts +16 -0
- package/dist/components/init/TestCheckStep.d.ts.map +1 -0
- package/dist/components/init/TestCheckStep.js +120 -0
- package/dist/components/init/TestCheckStep.js.map +1 -0
- package/dist/components/init/index.d.ts +1 -0
- package/dist/components/init/index.d.ts.map +1 -1
- package/dist/components/init/index.js +1 -0
- package/dist/components/init/index.js.map +1 -1
- package/dist/components/init/types.d.ts +9 -0
- package/dist/components/init/types.d.ts.map +1 -1
- package/dist/components/screens/InitScreen.d.ts.map +1 -1
- package/dist/components/screens/InitScreen.js +69 -6
- package/dist/components/screens/InitScreen.js.map +1 -1
- package/dist/components/screens/StartScreen.d.ts.map +1 -1
- package/dist/components/screens/StartScreen.js +89 -3
- package/dist/components/screens/StartScreen.js.map +1 -1
- package/dist/services/ConfigService.d.ts +1 -0
- package/dist/services/ConfigService.d.ts.map +1 -1
- package/dist/services/ConfigService.js.map +1 -1
- package/dist/services/ProjectDetector.d.ts +28 -0
- package/dist/services/ProjectDetector.d.ts.map +1 -0
- package/dist/services/ProjectDetector.js +236 -0
- package/dist/services/ProjectDetector.js.map +1 -0
- package/dist/services/TestRunner.d.ts +46 -0
- package/dist/services/TestRunner.d.ts.map +1 -0
- package/dist/services/TestRunner.js +85 -0
- package/dist/services/TestRunner.js.map +1 -0
- package/dist/services/index.d.ts +2 -0
- package/dist/services/index.d.ts.map +1 -1
- package/dist/services/index.js +2 -0
- package/dist/services/index.js.map +1 -1
- package/dist/types/index.d.ts +1 -0
- package/dist/types/index.d.ts.map +1 -1
- package/dist/types/index.js.map +1 -1
- package/framework/agents/claude/.claude/agents/red64/spec-impl.md +131 -2
- package/framework/agents/claude/.claude/commands/red64/spec-impl.md +24 -0
- package/framework/agents/codex/.codex/agents/red64/spec-impl.md +131 -2
- package/framework/agents/codex/.codex/commands/red64/spec-impl.md +24 -0
- package/framework/stacks/generic/feedback.md +80 -0
- package/framework/stacks/nextjs/accessibility.md +437 -0
- package/framework/stacks/nextjs/api.md +431 -0
- package/framework/stacks/nextjs/coding-style.md +282 -0
- package/framework/stacks/nextjs/commenting.md +226 -0
- package/framework/stacks/nextjs/components.md +411 -0
- package/framework/stacks/nextjs/conventions.md +333 -0
- package/framework/stacks/nextjs/css.md +310 -0
- package/framework/stacks/nextjs/error-handling.md +442 -0
- package/framework/stacks/nextjs/feedback.md +124 -0
- package/framework/stacks/nextjs/migrations.md +332 -0
- package/framework/stacks/nextjs/models.md +362 -0
- package/framework/stacks/nextjs/queries.md +410 -0
- package/framework/stacks/nextjs/responsive.md +338 -0
- package/framework/stacks/nextjs/tech-stack.md +177 -0
- package/framework/stacks/nextjs/test-writing.md +475 -0
- package/framework/stacks/nextjs/validation.md +467 -0
- package/framework/stacks/python/api.md +468 -0
- package/framework/stacks/python/authentication.md +342 -0
- package/framework/stacks/python/code-quality.md +283 -0
- package/framework/stacks/python/code-refactoring.md +315 -0
- package/framework/stacks/python/coding-style.md +462 -0
- package/framework/stacks/python/conventions.md +399 -0
- package/framework/stacks/python/error-handling.md +512 -0
- package/framework/stacks/python/feedback.md +92 -0
- package/framework/stacks/python/implement-ai-llm.md +468 -0
- package/framework/stacks/python/migrations.md +388 -0
- package/framework/stacks/python/models.md +399 -0
- package/framework/stacks/python/python.md +232 -0
- package/framework/stacks/python/queries.md +451 -0
- package/framework/stacks/python/structure.md +245 -58
- package/framework/stacks/python/tech.md +92 -35
- package/framework/stacks/python/testing.md +380 -0
- package/framework/stacks/python/validation.md +471 -0
- package/framework/stacks/rails/authentication.md +176 -0
- package/framework/stacks/rails/code-quality.md +287 -0
- package/framework/stacks/rails/code-refactoring.md +299 -0
- package/framework/stacks/rails/feedback.md +130 -0
- package/framework/stacks/rails/implement-ai-llm-with-rubyllm.md +342 -0
- package/framework/stacks/rails/rails.md +301 -0
- package/framework/stacks/rails/rails8-best-practices.md +498 -0
- package/framework/stacks/rails/rails8-css.md +573 -0
- package/framework/stacks/rails/structure.md +140 -0
- package/framework/stacks/rails/tech.md +108 -0
- package/framework/stacks/react/code-quality.md +521 -0
- package/framework/stacks/react/components.md +625 -0
- package/framework/stacks/react/data-fetching.md +586 -0
- package/framework/stacks/react/feedback.md +110 -0
- package/framework/stacks/react/forms.md +694 -0
- package/framework/stacks/react/performance.md +640 -0
- package/framework/stacks/react/product.md +22 -9
- package/framework/stacks/react/state-management.md +472 -0
- package/framework/stacks/react/structure.md +351 -44
- package/framework/stacks/react/tech.md +219 -30
- package/framework/stacks/react/testing.md +690 -0
- package/package.json +1 -1
- package/framework/stacks/node/product.md +0 -27
- package/framework/stacks/node/structure.md +0 -82
- package/framework/stacks/node/tech.md +0 -63
|
@@ -0,0 +1,338 @@
|
|
|
1
|
+
# Responsive Design
|
|
2
|
+
|
|
3
|
+
Mobile-first responsive patterns for Next.js with Tailwind CSS v4, responsive images, fluid typography, and layout strategies.
|
|
4
|
+
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
## Philosophy
|
|
8
|
+
|
|
9
|
+
- **Mobile-first**: Start with the smallest screen, enhance upward
|
|
10
|
+
- **Content drives breakpoints**: Break when the content breaks, not at device widths
|
|
11
|
+
- **Fluid over fixed**: Use relative units and fluid scales; avoid pixel-perfect design
|
|
12
|
+
- **Performance on mobile**: Optimize images, minimize layout shift, respect slow networks
|
|
13
|
+
|
|
14
|
+
---
|
|
15
|
+
|
|
16
|
+
## Breakpoint Strategy
|
|
17
|
+
|
|
18
|
+
### Tailwind Defaults
|
|
19
|
+
|
|
20
|
+
| Breakpoint | Min Width | Typical Device |
|
|
21
|
+
|---|---|---|
|
|
22
|
+
| (default) | 0px | Mobile phones |
|
|
23
|
+
| `sm` | 640px | Large phones, landscape |
|
|
24
|
+
| `md` | 768px | Tablets |
|
|
25
|
+
| `lg` | 1024px | Small laptops |
|
|
26
|
+
| `xl` | 1280px | Desktops |
|
|
27
|
+
| `2xl` | 1536px | Large screens |
|
|
28
|
+
|
|
29
|
+
### Mobile-First Syntax
|
|
30
|
+
|
|
31
|
+
```typescript
|
|
32
|
+
// Tailwind classes apply at the breakpoint and UP
|
|
33
|
+
<div className="
|
|
34
|
+
px-4 // Mobile: 16px padding
|
|
35
|
+
sm:px-6 // >= 640px: 24px padding
|
|
36
|
+
lg:px-8 // >= 1024px: 32px padding
|
|
37
|
+
">
|
|
38
|
+
<div className="
|
|
39
|
+
grid
|
|
40
|
+
grid-cols-1 // Mobile: single column
|
|
41
|
+
sm:grid-cols-2 // >= 640px: 2 columns
|
|
42
|
+
lg:grid-cols-3 // >= 1024px: 3 columns
|
|
43
|
+
gap-4
|
|
44
|
+
sm:gap-6
|
|
45
|
+
">
|
|
46
|
+
{items.map((item) => (
|
|
47
|
+
<Card key={item.id} item={item} />
|
|
48
|
+
))}
|
|
49
|
+
</div>
|
|
50
|
+
</div>
|
|
51
|
+
```
|
|
52
|
+
|
|
53
|
+
### Custom Breakpoints (Tailwind v4)
|
|
54
|
+
|
|
55
|
+
```css
|
|
56
|
+
/* app/globals.css */
|
|
57
|
+
@theme {
|
|
58
|
+
--breakpoint-xs: 475px;
|
|
59
|
+
--breakpoint-3xl: 1920px;
|
|
60
|
+
}
|
|
61
|
+
```
|
|
62
|
+
|
|
63
|
+
---
|
|
64
|
+
|
|
65
|
+
## Layout Patterns
|
|
66
|
+
|
|
67
|
+
### Responsive Sidebar
|
|
68
|
+
|
|
69
|
+
```typescript
|
|
70
|
+
export function DashboardLayout({ children }: { children: React.ReactNode }) {
|
|
71
|
+
return (
|
|
72
|
+
<div className="flex min-h-screen flex-col lg:flex-row">
|
|
73
|
+
{/* Mobile: top nav, Desktop: sidebar */}
|
|
74
|
+
<aside className="
|
|
75
|
+
w-full border-b bg-muted/50 p-4
|
|
76
|
+
lg:w-64 lg:shrink-0 lg:border-b-0 lg:border-r lg:p-6
|
|
77
|
+
">
|
|
78
|
+
<nav>
|
|
79
|
+
<MobileNav className="lg:hidden" />
|
|
80
|
+
<DesktopNav className="hidden lg:block" />
|
|
81
|
+
</nav>
|
|
82
|
+
</aside>
|
|
83
|
+
<main className="flex-1 p-4 sm:p-6 lg:p-8">{children}</main>
|
|
84
|
+
</div>
|
|
85
|
+
);
|
|
86
|
+
}
|
|
87
|
+
```
|
|
88
|
+
|
|
89
|
+
### Responsive Grid
|
|
90
|
+
|
|
91
|
+
```typescript
|
|
92
|
+
// Card grid that adapts from 1 to 4 columns
|
|
93
|
+
<div className="grid grid-cols-1 gap-4 sm:grid-cols-2 lg:grid-cols-3 xl:grid-cols-4">
|
|
94
|
+
{items.map((item) => <ItemCard key={item.id} {...item} />)}
|
|
95
|
+
</div>
|
|
96
|
+
|
|
97
|
+
// Two-column content layout
|
|
98
|
+
<div className="grid gap-8 lg:grid-cols-[1fr_300px]">
|
|
99
|
+
<article>{mainContent}</article>
|
|
100
|
+
<aside className="hidden lg:block">{sidebar}</aside>
|
|
101
|
+
</div>
|
|
102
|
+
```
|
|
103
|
+
|
|
104
|
+
### Responsive Stack
|
|
105
|
+
|
|
106
|
+
```typescript
|
|
107
|
+
// Horizontal on desktop, vertical on mobile
|
|
108
|
+
<div className="flex flex-col gap-4 sm:flex-row sm:items-center sm:justify-between">
|
|
109
|
+
<h1 className="text-2xl font-bold">Dashboard</h1>
|
|
110
|
+
<div className="flex gap-2">
|
|
111
|
+
<Button variant="outline">Export</Button>
|
|
112
|
+
<Button>Create New</Button>
|
|
113
|
+
</div>
|
|
114
|
+
</div>
|
|
115
|
+
```
|
|
116
|
+
|
|
117
|
+
---
|
|
118
|
+
|
|
119
|
+
## Container Queries
|
|
120
|
+
|
|
121
|
+
### Tailwind v4 Container Queries
|
|
122
|
+
|
|
123
|
+
```typescript
|
|
124
|
+
// Parent container
|
|
125
|
+
<div className="@container">
|
|
126
|
+
<div className="
|
|
127
|
+
flex flex-col gap-2
|
|
128
|
+
@sm:flex-row @sm:items-center @sm:gap-4
|
|
129
|
+
@lg:gap-6
|
|
130
|
+
">
|
|
131
|
+
<Avatar user={user} />
|
|
132
|
+
<div>
|
|
133
|
+
<h3 className="font-semibold">{user.name}</h3>
|
|
134
|
+
<p className="text-muted-foreground hidden @md:block">{user.bio}</p>
|
|
135
|
+
</div>
|
|
136
|
+
</div>
|
|
137
|
+
</div>
|
|
138
|
+
```
|
|
139
|
+
|
|
140
|
+
### When to Use Container vs Media Queries
|
|
141
|
+
|
|
142
|
+
| Approach | Use When |
|
|
143
|
+
|---|---|
|
|
144
|
+
| Media queries (`sm:`, `lg:`) | Page-level layout changes |
|
|
145
|
+
| Container queries (`@sm:`, `@lg:`) | Component adapts to its container width |
|
|
146
|
+
|
|
147
|
+
**Rule**: Use container queries for reusable components that appear in different-width containers (sidebars, grids, modals).
|
|
148
|
+
|
|
149
|
+
---
|
|
150
|
+
|
|
151
|
+
## Responsive Images
|
|
152
|
+
|
|
153
|
+
### Next.js Image Component
|
|
154
|
+
|
|
155
|
+
```typescript
|
|
156
|
+
import Image from "next/image";
|
|
157
|
+
|
|
158
|
+
// Responsive image that fills container
|
|
159
|
+
<div className="relative aspect-video w-full">
|
|
160
|
+
<Image
|
|
161
|
+
src="/hero.jpg"
|
|
162
|
+
alt="Hero banner"
|
|
163
|
+
fill
|
|
164
|
+
sizes="(max-width: 768px) 100vw, (max-width: 1200px) 50vw, 33vw"
|
|
165
|
+
className="rounded-lg object-cover"
|
|
166
|
+
priority // Above the fold: skip lazy loading
|
|
167
|
+
/>
|
|
168
|
+
</div>
|
|
169
|
+
|
|
170
|
+
// Fixed-size responsive avatar
|
|
171
|
+
<Image
|
|
172
|
+
src={user.avatarUrl}
|
|
173
|
+
alt={user.name}
|
|
174
|
+
width={48}
|
|
175
|
+
height={48}
|
|
176
|
+
className="h-12 w-12 rounded-full sm:h-16 sm:w-16"
|
|
177
|
+
sizes="(max-width: 640px) 48px, 64px"
|
|
178
|
+
/>
|
|
179
|
+
```
|
|
180
|
+
|
|
181
|
+
### The `sizes` Attribute
|
|
182
|
+
|
|
183
|
+
```typescript
|
|
184
|
+
// Tell the browser how wide the image will be at each breakpoint
|
|
185
|
+
// so it can pick the right srcset image
|
|
186
|
+
|
|
187
|
+
// Full width on mobile, half on tablet, third on desktop
|
|
188
|
+
sizes="(max-width: 768px) 100vw, (max-width: 1200px) 50vw, 33vw"
|
|
189
|
+
|
|
190
|
+
// Fixed width that changes at breakpoint
|
|
191
|
+
sizes="(max-width: 640px) 48px, 64px"
|
|
192
|
+
```
|
|
193
|
+
|
|
194
|
+
**Rule**: Always provide `sizes` when using `fill` or responsive images. Without it, the browser downloads the largest image regardless of viewport.
|
|
195
|
+
|
|
196
|
+
---
|
|
197
|
+
|
|
198
|
+
## Fluid Typography
|
|
199
|
+
|
|
200
|
+
### Clamp-Based Scaling
|
|
201
|
+
|
|
202
|
+
```css
|
|
203
|
+
/* app/globals.css */
|
|
204
|
+
@theme {
|
|
205
|
+
--font-size-fluid-sm: clamp(0.875rem, 0.8rem + 0.25vw, 1rem);
|
|
206
|
+
--font-size-fluid-base: clamp(1rem, 0.9rem + 0.35vw, 1.125rem);
|
|
207
|
+
--font-size-fluid-lg: clamp(1.25rem, 1rem + 0.75vw, 1.5rem);
|
|
208
|
+
--font-size-fluid-xl: clamp(1.5rem, 1.1rem + 1.25vw, 2.25rem);
|
|
209
|
+
--font-size-fluid-2xl: clamp(2rem, 1.2rem + 2.5vw, 3rem);
|
|
210
|
+
}
|
|
211
|
+
```
|
|
212
|
+
|
|
213
|
+
```typescript
|
|
214
|
+
// Usage
|
|
215
|
+
<h1 className="text-[length:var(--font-size-fluid-2xl)] font-bold">
|
|
216
|
+
Welcome Back
|
|
217
|
+
</h1>
|
|
218
|
+
<p className="text-[length:var(--font-size-fluid-base)]">
|
|
219
|
+
Here is your dashboard overview.
|
|
220
|
+
</p>
|
|
221
|
+
```
|
|
222
|
+
|
|
223
|
+
### Responsive Text with Tailwind
|
|
224
|
+
|
|
225
|
+
```typescript
|
|
226
|
+
// Simple breakpoint-based sizing
|
|
227
|
+
<h1 className="text-2xl font-bold sm:text-3xl lg:text-4xl">
|
|
228
|
+
Page Title
|
|
229
|
+
</h1>
|
|
230
|
+
|
|
231
|
+
// Truncation on small screens
|
|
232
|
+
<p className="truncate sm:whitespace-normal">
|
|
233
|
+
{longDescription}
|
|
234
|
+
</p>
|
|
235
|
+
```
|
|
236
|
+
|
|
237
|
+
---
|
|
238
|
+
|
|
239
|
+
## Touch Targets
|
|
240
|
+
|
|
241
|
+
### Minimum Sizes
|
|
242
|
+
|
|
243
|
+
```typescript
|
|
244
|
+
// Minimum 44x44px touch target (WCAG 2.5.5)
|
|
245
|
+
<button className="min-h-[44px] min-w-[44px] p-2">
|
|
246
|
+
<TrashIcon className="h-5 w-5" />
|
|
247
|
+
</button>
|
|
248
|
+
|
|
249
|
+
// Icon button with adequate touch area
|
|
250
|
+
<button className="inline-flex h-10 w-10 items-center justify-center rounded-md hover:bg-muted">
|
|
251
|
+
<MenuIcon className="h-5 w-5" />
|
|
252
|
+
</button>
|
|
253
|
+
|
|
254
|
+
// Link list with sufficient spacing
|
|
255
|
+
<nav>
|
|
256
|
+
<ul className="space-y-1">
|
|
257
|
+
{links.map((link) => (
|
|
258
|
+
<li key={link.href}>
|
|
259
|
+
<Link href={link.href} className="block rounded-md px-3 py-2 hover:bg-muted">
|
|
260
|
+
{link.label}
|
|
261
|
+
</Link>
|
|
262
|
+
</li>
|
|
263
|
+
))}
|
|
264
|
+
</ul>
|
|
265
|
+
</nav>
|
|
266
|
+
```
|
|
267
|
+
|
|
268
|
+
---
|
|
269
|
+
|
|
270
|
+
## Viewport Units
|
|
271
|
+
|
|
272
|
+
```typescript
|
|
273
|
+
// Full viewport height (mobile-safe)
|
|
274
|
+
<div className="min-h-dvh flex items-center justify-center">
|
|
275
|
+
<LoginForm />
|
|
276
|
+
</div>
|
|
277
|
+
|
|
278
|
+
// Sticky header that accounts for mobile browser chrome
|
|
279
|
+
<header className="sticky top-0 z-40 h-14 border-b bg-background/95 backdrop-blur supports-[backdrop-filter]:bg-background/60">
|
|
280
|
+
<nav className="container flex h-full items-center">
|
|
281
|
+
{/* ... */}
|
|
282
|
+
</nav>
|
|
283
|
+
</header>
|
|
284
|
+
```
|
|
285
|
+
|
|
286
|
+
| Unit | Behavior |
|
|
287
|
+
|---|---|
|
|
288
|
+
| `vh` | Static viewport height (ignores mobile browser chrome) |
|
|
289
|
+
| `dvh` | Dynamic viewport height (accounts for mobile URL bar) |
|
|
290
|
+
| `svh` | Smallest viewport height |
|
|
291
|
+
| `lvh` | Largest viewport height |
|
|
292
|
+
|
|
293
|
+
**Rule**: Use `dvh` for full-page layouts on mobile. Use `vh` only for non-critical measurements.
|
|
294
|
+
|
|
295
|
+
---
|
|
296
|
+
|
|
297
|
+
## Responsive Tables
|
|
298
|
+
|
|
299
|
+
```typescript
|
|
300
|
+
// Stack on mobile, table on desktop
|
|
301
|
+
<div className="overflow-x-auto">
|
|
302
|
+
<table className="w-full min-w-[600px]">
|
|
303
|
+
<thead className="hidden sm:table-header-group">
|
|
304
|
+
<tr>
|
|
305
|
+
<th>Name</th>
|
|
306
|
+
<th>Email</th>
|
|
307
|
+
<th>Role</th>
|
|
308
|
+
</tr>
|
|
309
|
+
</thead>
|
|
310
|
+
<tbody>
|
|
311
|
+
{users.map((user) => (
|
|
312
|
+
<tr key={user.id} className="flex flex-col border-b p-4 sm:table-row sm:p-0">
|
|
313
|
+
<td className="font-medium sm:p-3" data-label="Name">{user.name}</td>
|
|
314
|
+
<td className="text-muted-foreground sm:p-3" data-label="Email">{user.email}</td>
|
|
315
|
+
<td className="sm:p-3" data-label="Role"><Badge>{user.role}</Badge></td>
|
|
316
|
+
</tr>
|
|
317
|
+
))}
|
|
318
|
+
</tbody>
|
|
319
|
+
</table>
|
|
320
|
+
</div>
|
|
321
|
+
```
|
|
322
|
+
|
|
323
|
+
---
|
|
324
|
+
|
|
325
|
+
## Anti-Patterns
|
|
326
|
+
|
|
327
|
+
| Anti-Pattern | Problem | Correct Approach |
|
|
328
|
+
|---|---|---|
|
|
329
|
+
| Desktop-first CSS | Mobile styles require overrides | Start with mobile, enhance upward |
|
|
330
|
+
| Fixed pixel widths | Does not adapt to screen size | Use percentages, `max-w-*`, or grid |
|
|
331
|
+
| Missing `sizes` on images | Browser downloads oversized images | Always specify `sizes` with responsive images |
|
|
332
|
+
| Horizontal scroll on mobile | Content cut off or hidden | Test at 320px width minimum |
|
|
333
|
+
| Small touch targets | Frustrating on mobile, a11y failure | Minimum 44x44px tap area |
|
|
334
|
+
| Using `vh` for full-height layouts | Broken on mobile browsers | Use `dvh` or `min-h-screen` |
|
|
335
|
+
|
|
336
|
+
---
|
|
337
|
+
|
|
338
|
+
_Design for the smallest screen first, then add complexity. If it works on a phone, it will work everywhere._
|
|
@@ -0,0 +1,177 @@
|
|
|
1
|
+
# Tech Stack
|
|
2
|
+
|
|
3
|
+
Complete technology stack for Next.js 15 App Router projects with TypeScript, Tailwind CSS v4, Prisma, and NextAuth.js.
|
|
4
|
+
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
## Philosophy
|
|
8
|
+
|
|
9
|
+
- **Full-stack TypeScript**: One language from database to browser, shared types everywhere
|
|
10
|
+
- **Server-first**: Default to server components and server-side data fetching
|
|
11
|
+
- **Edge-ready**: Architecture that works on serverless and edge runtimes
|
|
12
|
+
- **Convention over configuration**: Leverage framework defaults before reaching for custom solutions
|
|
13
|
+
|
|
14
|
+
---
|
|
15
|
+
|
|
16
|
+
## Core Stack
|
|
17
|
+
|
|
18
|
+
| Layer | Technology | Version | Purpose |
|
|
19
|
+
|---|---|---|---|
|
|
20
|
+
| Framework | Next.js | 15 | Full-stack React framework with App Router |
|
|
21
|
+
| Language | TypeScript | 5.x | Strict mode, type-safe across the stack |
|
|
22
|
+
| Styling | Tailwind CSS | 4.x | Utility-first CSS with CSS-first configuration |
|
|
23
|
+
| ORM | Prisma | 6.x | Type-safe database access with migrations |
|
|
24
|
+
| Auth | NextAuth.js | 5.x | Authentication with multiple providers |
|
|
25
|
+
| Runtime | Node.js | 20+ | LTS runtime for server-side execution |
|
|
26
|
+
| Package Manager | pnpm | 9.x | Fast, disk-efficient package management |
|
|
27
|
+
|
|
28
|
+
---
|
|
29
|
+
|
|
30
|
+
## Frontend Stack
|
|
31
|
+
|
|
32
|
+
### UI Layer
|
|
33
|
+
|
|
34
|
+
| Technology | Purpose | Notes |
|
|
35
|
+
|---|---|---|
|
|
36
|
+
| React | 19 with Server Components | Default to RSC, opt into client when needed |
|
|
37
|
+
| Tailwind CSS v4 | Styling | CSS-first config via `@theme` in CSS |
|
|
38
|
+
| class-variance-authority | Component variants | Type-safe variant props |
|
|
39
|
+
| clsx + tailwind-merge | Class merging | `cn()` utility for conditional classes |
|
|
40
|
+
| Lucide React | Icons | Tree-shakeable SVG icon library |
|
|
41
|
+
| next/image | Image optimization | Automatic WebP/AVIF, lazy loading |
|
|
42
|
+
| next/font | Font optimization | Zero layout shift, self-hosted fonts |
|
|
43
|
+
|
|
44
|
+
### State and Data
|
|
45
|
+
|
|
46
|
+
| Technology | Purpose | Notes |
|
|
47
|
+
|---|---|---|
|
|
48
|
+
| React Server Components | Server-side data | No client bundle, direct DB access |
|
|
49
|
+
| Server Actions | Mutations | Type-safe form submissions |
|
|
50
|
+
| nuqs | URL state | Type-safe search params management |
|
|
51
|
+
| React Hook Form | Form state | Client-side form management with zod |
|
|
52
|
+
| SWR or TanStack Query | Client caching | Only when RSC is insufficient |
|
|
53
|
+
|
|
54
|
+
---
|
|
55
|
+
|
|
56
|
+
## Backend Stack
|
|
57
|
+
|
|
58
|
+
### Data Layer
|
|
59
|
+
|
|
60
|
+
| Technology | Purpose | Notes |
|
|
61
|
+
|---|---|---|
|
|
62
|
+
| Prisma Client | Query builder | Generated types from schema |
|
|
63
|
+
| Prisma Migrate | Schema migrations | Version-controlled database changes |
|
|
64
|
+
| PostgreSQL | Production database | Via Neon, Supabase, or self-hosted |
|
|
65
|
+
| SQLite | Development database | Zero-config local development |
|
|
66
|
+
|
|
67
|
+
### Authentication
|
|
68
|
+
|
|
69
|
+
| Technology | Purpose | Notes |
|
|
70
|
+
|---|---|---|
|
|
71
|
+
| NextAuth.js v5 | Auth framework | App Router native, edge-compatible |
|
|
72
|
+
| @auth/prisma-adapter | Session storage | Database-backed sessions |
|
|
73
|
+
| bcrypt | Password hashing | For credentials provider |
|
|
74
|
+
|
|
75
|
+
### API and Validation
|
|
76
|
+
|
|
77
|
+
| Technology | Purpose | Notes |
|
|
78
|
+
|---|---|---|
|
|
79
|
+
| Route Handlers | REST endpoints | `app/api/**/route.ts` |
|
|
80
|
+
| Server Actions | Mutations | `"use server"` functions |
|
|
81
|
+
| Zod | Schema validation | Shared between client and server |
|
|
82
|
+
|
|
83
|
+
---
|
|
84
|
+
|
|
85
|
+
## Testing Stack
|
|
86
|
+
|
|
87
|
+
| Technology | Purpose | Notes |
|
|
88
|
+
|---|---|---|
|
|
89
|
+
| Vitest | Unit and integration tests | Fast, ESM-native, Jest-compatible API |
|
|
90
|
+
| React Testing Library | Component testing | DOM-based, accessibility-focused |
|
|
91
|
+
| Playwright | End-to-end testing | Cross-browser, auto-waiting |
|
|
92
|
+
| MSW | API mocking | Service worker interception |
|
|
93
|
+
|
|
94
|
+
### Test Commands
|
|
95
|
+
|
|
96
|
+
```bash
|
|
97
|
+
# Unit and integration tests
|
|
98
|
+
pnpm vitest run
|
|
99
|
+
|
|
100
|
+
# Component tests with coverage
|
|
101
|
+
pnpm vitest run --coverage
|
|
102
|
+
|
|
103
|
+
# E2E tests
|
|
104
|
+
pnpm playwright test
|
|
105
|
+
|
|
106
|
+
# E2E with UI mode
|
|
107
|
+
pnpm playwright test --ui
|
|
108
|
+
```
|
|
109
|
+
|
|
110
|
+
---
|
|
111
|
+
|
|
112
|
+
## Development Tools
|
|
113
|
+
|
|
114
|
+
| Tool | Purpose | Configuration |
|
|
115
|
+
|---|---|---|
|
|
116
|
+
| ESLint | Linting | `eslint.config.mjs` with flat config |
|
|
117
|
+
| Prettier | Formatting | `.prettierrc` with Tailwind plugin |
|
|
118
|
+
| TypeScript | Type checking | `tsconfig.json` with strict mode |
|
|
119
|
+
| Prisma Studio | Database GUI | `pnpm prisma studio` |
|
|
120
|
+
| next dev --turbopack | Dev server | Turbopack for fast refresh |
|
|
121
|
+
|
|
122
|
+
### Editor Setup
|
|
123
|
+
|
|
124
|
+
```jsonc
|
|
125
|
+
// .vscode/settings.json
|
|
126
|
+
{
|
|
127
|
+
"editor.defaultFormatter": "esbenp.prettier-vscode",
|
|
128
|
+
"editor.formatOnSave": true,
|
|
129
|
+
"editor.codeActionsOnSave": {
|
|
130
|
+
"source.fixAll.eslint": "explicit"
|
|
131
|
+
},
|
|
132
|
+
"typescript.preferences.importModuleSpecifier": "non-relative"
|
|
133
|
+
}
|
|
134
|
+
```
|
|
135
|
+
|
|
136
|
+
---
|
|
137
|
+
|
|
138
|
+
## Deployment
|
|
139
|
+
|
|
140
|
+
| Component | Technology | Notes |
|
|
141
|
+
|---|---|---|
|
|
142
|
+
| Hosting | Vercel | Native Next.js support, edge functions |
|
|
143
|
+
| CI/CD | GitHub Actions | Lint, type-check, test, deploy |
|
|
144
|
+
| Database | Neon / Supabase | Serverless PostgreSQL with connection pooling |
|
|
145
|
+
| Monitoring | Sentry | Error tracking with source maps |
|
|
146
|
+
| Analytics | Vercel Analytics | Core Web Vitals, real user metrics |
|
|
147
|
+
|
|
148
|
+
### Environment Variables
|
|
149
|
+
|
|
150
|
+
```bash
|
|
151
|
+
# .env.local (never committed)
|
|
152
|
+
DATABASE_URL="postgresql://..."
|
|
153
|
+
NEXTAUTH_SECRET="..."
|
|
154
|
+
NEXTAUTH_URL="http://localhost:3000"
|
|
155
|
+
|
|
156
|
+
# .env (defaults, committed)
|
|
157
|
+
NEXT_PUBLIC_APP_NAME="MyApp"
|
|
158
|
+
```
|
|
159
|
+
|
|
160
|
+
---
|
|
161
|
+
|
|
162
|
+
## Key Architectural Decisions
|
|
163
|
+
|
|
164
|
+
| Decision | Choice | Rationale |
|
|
165
|
+
|---|---|---|
|
|
166
|
+
| Rendering | Server Components first | Smaller bundles, direct data access |
|
|
167
|
+
| Routing | App Router | Layouts, loading states, streaming |
|
|
168
|
+
| Styling | Tailwind v4 | CSS-first config, no JS overhead |
|
|
169
|
+
| ORM | Prisma | Best TypeScript DX, migration tooling |
|
|
170
|
+
| Auth | NextAuth v5 | App Router native, multiple providers |
|
|
171
|
+
| Testing | Vitest + Playwright | Fast unit tests, reliable E2E |
|
|
172
|
+
| State | URL + Server Components | Minimal client state, shareable URLs |
|
|
173
|
+
| Forms | Server Actions + react-hook-form | Progressive enhancement, type safety |
|
|
174
|
+
|
|
175
|
+
---
|
|
176
|
+
|
|
177
|
+
_Choose boring technology. Every dependency is a liability. Add tools only when the framework defaults fall short._
|