@zigrivers/scaffold 3.5.3 → 3.7.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.
Files changed (89) hide show
  1. package/README.md +150 -8
  2. package/content/knowledge/backend/backend-api-design.md +103 -0
  3. package/content/knowledge/backend/backend-architecture.md +100 -0
  4. package/content/knowledge/backend/backend-async-patterns.md +101 -0
  5. package/content/knowledge/backend/backend-auth-patterns.md +100 -0
  6. package/content/knowledge/backend/backend-conventions.md +105 -0
  7. package/content/knowledge/backend/backend-data-modeling.md +102 -0
  8. package/content/knowledge/backend/backend-deployment.md +100 -0
  9. package/content/knowledge/backend/backend-dev-environment.md +102 -0
  10. package/content/knowledge/backend/backend-observability.md +102 -0
  11. package/content/knowledge/backend/backend-project-structure.md +100 -0
  12. package/content/knowledge/backend/backend-requirements.md +103 -0
  13. package/content/knowledge/backend/backend-security.md +104 -0
  14. package/content/knowledge/backend/backend-testing.md +101 -0
  15. package/content/knowledge/backend/backend-worker-patterns.md +100 -0
  16. package/content/knowledge/cli/cli-architecture.md +101 -0
  17. package/content/knowledge/cli/cli-conventions.md +117 -0
  18. package/content/knowledge/cli/cli-dev-environment.md +121 -0
  19. package/content/knowledge/cli/cli-distribution-patterns.md +106 -0
  20. package/content/knowledge/cli/cli-interactivity-patterns.md +116 -0
  21. package/content/knowledge/cli/cli-output-patterns.md +107 -0
  22. package/content/knowledge/cli/cli-project-structure.md +124 -0
  23. package/content/knowledge/cli/cli-requirements.md +101 -0
  24. package/content/knowledge/cli/cli-shell-integration.md +130 -0
  25. package/content/knowledge/cli/cli-testing.md +134 -0
  26. package/content/knowledge/web-app/web-app-api-patterns.md +224 -0
  27. package/content/knowledge/web-app/web-app-architecture.md +116 -0
  28. package/content/knowledge/web-app/web-app-auth-patterns.md +256 -0
  29. package/content/knowledge/web-app/web-app-conventions.md +121 -0
  30. package/content/knowledge/web-app/web-app-data-patterns.md +218 -0
  31. package/content/knowledge/web-app/web-app-deployment-workflow.md +143 -0
  32. package/content/knowledge/web-app/web-app-deployment.md +134 -0
  33. package/content/knowledge/web-app/web-app-design-system.md +158 -0
  34. package/content/knowledge/web-app/web-app-dev-environment.md +173 -0
  35. package/content/knowledge/web-app/web-app-observability.md +221 -0
  36. package/content/knowledge/web-app/web-app-project-structure.md +160 -0
  37. package/content/knowledge/web-app/web-app-rendering-strategies.md +133 -0
  38. package/content/knowledge/web-app/web-app-requirements.md +112 -0
  39. package/content/knowledge/web-app/web-app-security.md +193 -0
  40. package/content/knowledge/web-app/web-app-session-patterns.md +214 -0
  41. package/content/knowledge/web-app/web-app-testing.md +249 -0
  42. package/content/knowledge/web-app/web-app-ux-patterns.md +162 -0
  43. package/content/methodology/backend-overlay.yml +73 -0
  44. package/content/methodology/cli-overlay.yml +69 -0
  45. package/content/methodology/web-app-overlay.yml +79 -0
  46. package/dist/cli/commands/init.d.ts +26 -0
  47. package/dist/cli/commands/init.d.ts.map +1 -1
  48. package/dist/cli/commands/init.js +354 -7
  49. package/dist/cli/commands/init.js.map +1 -1
  50. package/dist/cli/commands/init.test.js +136 -0
  51. package/dist/cli/commands/init.test.js.map +1 -1
  52. package/dist/config/schema.d.ts +800 -32
  53. package/dist/config/schema.d.ts.map +1 -1
  54. package/dist/config/schema.js +48 -5
  55. package/dist/config/schema.js.map +1 -1
  56. package/dist/config/schema.test.js +156 -1
  57. package/dist/config/schema.test.js.map +1 -1
  58. package/dist/core/assembly/overlay-loader.d.ts.map +1 -1
  59. package/dist/core/assembly/overlay-loader.js +2 -1
  60. package/dist/core/assembly/overlay-loader.js.map +1 -1
  61. package/dist/core/assembly/overlay-loader.test.js +34 -0
  62. package/dist/core/assembly/overlay-loader.test.js.map +1 -1
  63. package/dist/e2e/game-pipeline.test.js +1 -0
  64. package/dist/e2e/game-pipeline.test.js.map +1 -1
  65. package/dist/e2e/project-type-overlays.test.d.ts +15 -0
  66. package/dist/e2e/project-type-overlays.test.d.ts.map +1 -0
  67. package/dist/e2e/project-type-overlays.test.js +534 -0
  68. package/dist/e2e/project-type-overlays.test.js.map +1 -0
  69. package/dist/types/config.d.ts +13 -2
  70. package/dist/types/config.d.ts.map +1 -1
  71. package/dist/types/index.d.ts +0 -1
  72. package/dist/types/index.d.ts.map +1 -1
  73. package/dist/types/index.js +0 -1
  74. package/dist/types/index.js.map +1 -1
  75. package/dist/wizard/questions.d.ts +30 -1
  76. package/dist/wizard/questions.d.ts.map +1 -1
  77. package/dist/wizard/questions.js +181 -36
  78. package/dist/wizard/questions.js.map +1 -1
  79. package/dist/wizard/questions.test.js +334 -4
  80. package/dist/wizard/questions.test.js.map +1 -1
  81. package/dist/wizard/wizard.d.ts +26 -0
  82. package/dist/wizard/wizard.d.ts.map +1 -1
  83. package/dist/wizard/wizard.js +31 -2
  84. package/dist/wizard/wizard.js.map +1 -1
  85. package/package.json +1 -1
  86. package/dist/types/wizard.d.ts +0 -14
  87. package/dist/types/wizard.d.ts.map +0 -1
  88. package/dist/types/wizard.js +0 -2
  89. package/dist/types/wizard.js.map +0 -1
@@ -0,0 +1,221 @@
1
+ ---
2
+ name: web-app-observability
3
+ description: Real User Monitoring, Core Web Vitals tracking, error tracking with Sentry, CDN analytics, custom performance marks, and performance regression alerting
4
+ topics: [web-app, observability, rum, core-web-vitals, sentry, performance, monitoring]
5
+ ---
6
+
7
+ You cannot improve what you cannot measure. Frontend observability is often treated as an afterthought — added after users start complaining — but by then you have no baseline to regress against and no historical data to understand when performance degraded or errors started. Real User Monitoring (RUM) captures the experience of your actual users on their actual devices and networks, which lab-based tests like Lighthouse cannot replicate. Core Web Vitals are Google's standardized metrics for page experience and directly influence search ranking.
8
+
9
+ ## Summary
10
+
11
+ ### Real User Monitoring (RUM)
12
+
13
+ RUM collects performance and behavioral data from real user sessions in production. Unlike synthetic monitoring (scheduled tests from a data center), RUM reflects the diversity of real-world conditions: slow Android devices, congested mobile networks, aggressive ad blockers, and geographically distant users.
14
+
15
+ **Key RUM metrics:**
16
+
17
+ - **Core Web Vitals** — Google's page experience signals (see below)
18
+ - **Time to First Byte (TTFB)** — server response latency
19
+ - **First Contentful Paint (FCP)** — when the first content is painted
20
+ - **Time to Interactive (TTI)** — when the page is reliably interactive
21
+ - **Custom marks** — application-specific milestones (e.g., "dashboard data loaded")
22
+ - **Error rate** — JavaScript exceptions per session
23
+ - **Rage clicks** — repeated clicks on non-interactive elements (UX frustration signal)
24
+ - **Dead clicks** — clicks on elements that produce no response
25
+
26
+ **RUM tools:** Vercel Analytics, Datadog RUM, New Relic Browser, Sentry Performance, web-vitals library (self-hosted reporting).
27
+
28
+ ### Core Web Vitals
29
+
30
+ Google's three Core Web Vitals measure loading, interactivity, and visual stability:
31
+
32
+ | Metric | Measures | Good | Needs Improvement | Poor |
33
+ |---|---|---|---|---|
34
+ | **LCP** (Largest Contentful Paint) | Load performance | ≤ 2.5s | 2.5–4s | > 4s |
35
+ | **INP** (Interaction to Next Paint) | Responsiveness | ≤ 200ms | 200–500ms | > 500ms |
36
+ | **CLS** (Cumulative Layout Shift) | Visual stability | ≤ 0.1 | 0.1–0.25 | > 0.25 |
37
+
38
+ **Common LCP causes and fixes:**
39
+ - Unoptimized hero images → use `srcset`, WebP/AVIF, CDN, `loading="eager"`, `fetchpriority="high"`
40
+ - Render-blocking CSS/fonts → inline critical CSS, use `font-display: swap`
41
+ - Slow TTFB → edge caching, CDN, server-side optimization
42
+
43
+ **Common CLS causes and fixes:**
44
+ - Images without explicit `width`/`height` attributes → always set dimensions
45
+ - Late-loading ads or embeds → reserve space with aspect-ratio boxes
46
+ - Custom fonts causing text reflow → use `font-display: optional` or `size-adjust`
47
+ - Dynamic content injected above viewport content → append below, not prepend above
48
+
49
+ **INP (replaced FID in 2024):** Measures the responsiveness of all user interactions, not just the first. Long JavaScript tasks (>50ms) block the main thread and inflate INP. Use `scheduler.postTask()`, web workers, and code splitting to break up long tasks.
50
+
51
+ ### Error Tracking with Sentry
52
+
53
+ Sentry captures JavaScript exceptions, stack traces, user context, and breadcrumbs (the sequence of events leading to the error). Configure it to filter noise and surface actionable errors.
54
+
55
+ **Critical Sentry configuration:**
56
+ - Source maps for readable stack traces (never ship source maps publicly — upload to Sentry only)
57
+ - User context (attach user ID, plan tier — never PII like email without consent)
58
+ - Release tracking to correlate error spikes with deployments
59
+ - Sampling rate: 100% for errors, 10–20% for performance transactions in high-traffic apps
60
+
61
+ ### Performance Regression Alerting
62
+
63
+ The goal is to catch regressions before they reach users or before they compound. Alert on:
64
+ - LCP p75 (75th percentile) increases by more than 300ms from the rolling 7-day average
65
+ - Error rate increases by more than 0.5% from the rolling 24-hour baseline
66
+ - Any new error type appearing in production for the first time
67
+
68
+ ## Deep Guidance
69
+
70
+ ### Web Vitals Collection
71
+
72
+ ```typescript
73
+ // web-vitals library — collect and report Core Web Vitals
74
+ import { onLCP, onINP, onCLS, onFCP, onTTFB } from 'web-vitals';
75
+
76
+ function sendToAnalytics(metric: any) {
77
+ // Batch metrics to avoid sending too many beacons
78
+ const body = JSON.stringify({
79
+ name: metric.name,
80
+ value: metric.value,
81
+ rating: metric.rating, // 'good', 'needs-improvement', 'poor'
82
+ id: metric.id,
83
+ navigationType: metric.navigationType,
84
+ url: window.location.pathname,
85
+ // Attach context for segmentation
86
+ connectionType: (navigator as any).connection?.effectiveType,
87
+ deviceMemory: (navigator as any).deviceMemory,
88
+ });
89
+
90
+ // sendBeacon is non-blocking and survives page unload
91
+ if (navigator.sendBeacon) {
92
+ navigator.sendBeacon('/api/vitals', body);
93
+ } else {
94
+ fetch('/api/vitals', { method: 'POST', body, keepalive: true });
95
+ }
96
+ }
97
+
98
+ // Register all Core Web Vitals + FCP + TTFB
99
+ onLCP(sendToAnalytics);
100
+ onINP(sendToAnalytics);
101
+ onCLS(sendToAnalytics);
102
+ onFCP(sendToAnalytics);
103
+ onTTFB(sendToAnalytics);
104
+ ```
105
+
106
+ Always use `navigator.sendBeacon` for analytics reporting — it queues the request to be sent after the page unloads without blocking navigation.
107
+
108
+ ### Custom Performance Marks
109
+
110
+ Use the User Timing API to measure application-specific milestones that browser APIs cannot capture:
111
+
112
+ ```typescript
113
+ // Mark application-level performance milestones
114
+ class PerformanceTracker {
115
+ private marks: Map<string, number> = new Map();
116
+
117
+ mark(name: string): void {
118
+ performance.mark(name);
119
+ this.marks.set(name, performance.now());
120
+ }
121
+
122
+ measure(name: string, startMark: string, endMark?: string): number {
123
+ const end = endMark || name + '-end';
124
+ if (!endMark) this.mark(end);
125
+
126
+ const measure = performance.measure(name, startMark, end);
127
+ const duration = measure.duration;
128
+
129
+ // Report to RUM
130
+ this.report({ name, duration });
131
+ return duration;
132
+ }
133
+
134
+ private report(metric: { name: string; duration: number }): void {
135
+ navigator.sendBeacon?.('/api/perf', JSON.stringify(metric));
136
+ }
137
+ }
138
+
139
+ const perf = new PerformanceTracker();
140
+
141
+ // Usage in application code
142
+ async function loadDashboard() {
143
+ perf.mark('dashboard-fetch-start');
144
+ const data = await fetchDashboardData();
145
+ perf.mark('dashboard-fetch-end');
146
+
147
+ perf.measure('dashboard-fetch', 'dashboard-fetch-start', 'dashboard-fetch-end');
148
+
149
+ perf.mark('dashboard-render-start');
150
+ renderDashboard(data);
151
+ perf.mark('dashboard-render-end');
152
+
153
+ perf.measure('dashboard-render', 'dashboard-render-start', 'dashboard-render-end');
154
+ }
155
+ ```
156
+
157
+ These custom marks appear in Chrome DevTools Performance panel and can be reported to your RUM backend for tracking.
158
+
159
+ ### Sentry Setup for Next.js
160
+
161
+ ```typescript
162
+ // sentry.client.config.ts
163
+ import * as Sentry from '@sentry/nextjs';
164
+
165
+ Sentry.init({
166
+ dsn: process.env.NEXT_PUBLIC_SENTRY_DSN,
167
+ environment: process.env.NEXT_PUBLIC_ENV,
168
+
169
+ // Performance monitoring sample rate — adjust based on traffic volume
170
+ tracesSampleRate: process.env.NODE_ENV === 'production' ? 0.1 : 1.0,
171
+
172
+ // Replay for error sessions only (privacy-conscious default)
173
+ replaysOnErrorSampleRate: 1.0,
174
+ replaysSessionSampleRate: 0.0,
175
+
176
+ // Filter noise — don't track network errors from ad blockers
177
+ ignoreErrors: [
178
+ 'ResizeObserver loop limit exceeded',
179
+ 'Non-Error promise rejection captured',
180
+ /Loading chunk \d+ failed/,
181
+ ],
182
+
183
+ beforeSend(event, hint) {
184
+ // Strip PII from error context
185
+ if (event.user) {
186
+ delete event.user.email;
187
+ delete event.user.username;
188
+ }
189
+ return event;
190
+ },
191
+
192
+ integrations: [
193
+ Sentry.replayIntegration({
194
+ maskAllText: true, // Privacy: mask all text in replays
195
+ blockAllMedia: true, // Privacy: block media in replays
196
+ }),
197
+ ],
198
+ });
199
+ ```
200
+
201
+ ### CDN Analytics and Cache Hit Rate
202
+
203
+ Monitor CDN cache performance as a leading indicator for LCP and TTFB:
204
+
205
+ - **Cache hit rate** — percentage of requests served from CDN cache vs origin. Target >90% for static assets, >70% for edge-cached HTML.
206
+ - **Origin shield hit rate** — for CDN tiers that include an origin shield, a low rate indicates cold cache or poor cache-control headers.
207
+ - **Edge latency by region** — identify geographic regions where users have poor performance; expand CDN PoP coverage or investigate origin latency.
208
+
209
+ Key cache-control headers:
210
+ ```
211
+ # Immutable static assets (hashed filenames)
212
+ Cache-Control: public, max-age=31536000, immutable
213
+
214
+ # HTML pages — revalidate frequently but serve stale while revalidating
215
+ Cache-Control: public, max-age=0, s-maxage=86400, stale-while-revalidate=3600
216
+
217
+ # API responses — no public cache, short browser cache
218
+ Cache-Control: private, max-age=30
219
+ ```
220
+
221
+ Set `Surrogate-Key` (Fastly) or `Cache-Tag` (Cloudflare) headers on HTML responses to enable targeted cache purging when content changes.
@@ -0,0 +1,160 @@
1
+ ---
2
+ name: web-app-project-structure
3
+ description: Directory layout conventions, route organization, shared vs feature modules, barrel exports, and config file placement for web apps
4
+ topics: [web-app, project-structure, architecture, routing, modules]
5
+ ---
6
+
7
+ A well-structured web app project is navigable by any developer without a tour. The directory layout should communicate the architecture at a glance: where pages live, where shared code lives, where API logic lives, and where configuration lives. A poor structure forces every developer to ask "where does this go?" on every new file they create.
8
+
9
+ ## Summary
10
+
11
+ Web app project structure separates `app/` (routes and layouts), `features/` (domain-owned modules), `components/` (shared UI), `hooks/` (shared hooks), and `lib/` (framework-agnostic utilities). Routes mirror URL structure with thin page files. Feature modules own their components, hooks, and types; shared modules have zero imports from feature modules.
12
+
13
+ ## Deep Guidance
14
+
15
+ ### Standard Directory Layout
16
+
17
+ For a Next.js or similar SSR framework, the canonical structure is:
18
+
19
+ ```
20
+ src/
21
+ app/ # App Router pages and layouts (Next.js 13+)
22
+ pages/ # Pages Router (Next.js legacy; or Remix/Vite routes)
23
+ components/ # Shared, reusable UI components
24
+ features/ # Feature modules (colocated components + hooks + logic)
25
+ hooks/ # Shared custom hooks used across features
26
+ lib/ # Framework-agnostic utilities and service clients
27
+ api/ # API route handlers (serverless functions)
28
+ types/ # Shared TypeScript types and interfaces
29
+ styles/ # Global CSS, design tokens, theme config
30
+ public/ # Static assets served at root (images, fonts, robots.txt)
31
+ ```
32
+
33
+ For a Vite/React SPA, drop `app/` and `api/` and substitute:
34
+
35
+ ```
36
+ src/
37
+ routes/ # Route components and nested layouts
38
+ pages/ # Page-level components (one per route)
39
+ ```
40
+
41
+ ### Route Organization
42
+
43
+ Routes should mirror the URL structure. Avoid flat route files that make the hierarchy ambiguous:
44
+
45
+ - `/dashboard` → `app/dashboard/page.tsx`
46
+ - `/dashboard/settings` → `app/dashboard/settings/page.tsx`
47
+ - `/users/[id]` → `app/users/[id]/page.tsx`
48
+
49
+ Keep route files thin — they orchestrate data loading and pass props to feature components. Business logic belongs in `features/`, not in the page file.
50
+
51
+ **Layouts**: Use layout files (`layout.tsx`) to share navigation, auth checks, and providers across route groups. Do not repeat these in every page file.
52
+
53
+ ### Shared vs Feature Modules
54
+
55
+ The critical distinction is "who owns this code":
56
+
57
+ - **Feature module** (`features/checkout/`): Owned by one product domain. Contains everything the checkout feature needs — components, hooks, API calls, types. Other features do not import from it directly; they use shared interfaces.
58
+ - **Shared module** (`components/`, `hooks/`, `lib/`): Owned by no single feature. Used by two or more features. Has no knowledge of any specific feature's business logic.
59
+
60
+ The rule: shared modules must have zero imports from feature modules. Feature modules may import from shared modules. This prevents circular dependencies and keeps shared code reusable.
61
+
62
+ ### Barrel Exports
63
+
64
+ Use `index.ts` barrel files at the feature and component directory level to create clean import paths:
65
+
66
+ ```typescript
67
+ // features/user-profile/index.ts
68
+ export { UserProfile } from "./UserProfile";
69
+ export { useUserProfile } from "./useUserProfile";
70
+ export type { UserProfileData } from "./user-profile.types";
71
+ ```
72
+
73
+ Consumers import from `features/user-profile`, not from deep internal paths:
74
+ ```typescript
75
+ // Good
76
+ import { UserProfile } from "@/features/user-profile";
77
+
78
+ // Bad — leaks internal structure
79
+ import { UserProfile } from "@/features/user-profile/components/UserProfile";
80
+ ```
81
+
82
+ Configure TypeScript path aliases (`@/`) to avoid relative path ladders (`../../../../../../`).
83
+
84
+ ### Config Files
85
+
86
+ Config files belong at the repo root, not inside `src/`. Standard placement:
87
+
88
+ - `next.config.ts` / `vite.config.ts` — build and bundler config
89
+ - `tsconfig.json` — TypeScript compiler config
90
+ - `eslint.config.js` — linting rules
91
+ - `.env.example` — documented environment variables (committed); `.env.local` — actual values (gitignored)
92
+ - `tailwind.config.ts` — if using Tailwind
93
+ - `vitest.config.ts` / `jest.config.ts` — test runner config
94
+
95
+ ### Feature Module Template
96
+
97
+ Every feature module follows the same internal structure. Establish this template in `CONTRIBUTING.md`:
98
+
99
+ ```
100
+ features/
101
+ <feature-name>/
102
+ index.ts # Barrel export — public API of the feature
103
+ <FeatureName>.tsx # Top-level feature component
104
+ <FeatureName>.test.tsx # Component tests
105
+ <FeatureName>.stories.tsx # Storybook stories (if applicable)
106
+ use<FeatureName>.ts # Primary data hook
107
+ use<FeatureName>.test.ts # Hook tests
108
+ <feature-name>.types.ts # TypeScript types for this feature
109
+ <feature-name>.api.ts # API calls made by this feature (if applicable)
110
+ components/ # Sub-components used only within this feature
111
+ <SubComponent>.tsx
112
+ ```
113
+
114
+ Enforce "no cross-feature imports" with ESLint:
115
+
116
+ ```javascript
117
+ // eslint-plugin-import rule to prevent cross-feature imports
118
+ "import/no-restricted-paths": [
119
+ "error",
120
+ {
121
+ "zones": [{
122
+ "target": "./src/features",
123
+ "from": "./src/features",
124
+ "except": ["./src/features/index.ts"] // Only barrel is importable
125
+ }]
126
+ }
127
+ ]
128
+ ```
129
+
130
+ ### Environment Variable Management
131
+
132
+ Never hardcode environment-specific values. Use `.env` files and document every variable:
133
+
134
+ ```bash
135
+ # .env.example — committed to the repo
136
+ # Never commit .env, .env.local, or .env.production
137
+
138
+ # API base URL
139
+ NEXT_PUBLIC_API_URL=https://api.example.com
140
+
141
+ # Auth provider
142
+ NEXT_PUBLIC_AUTH_DOMAIN=your-domain.auth0.com
143
+ AUTH_SECRET= # Server-only; never expose to client (no NEXT_PUBLIC_ prefix)
144
+
145
+ # Feature flags
146
+ NEXT_PUBLIC_FEATURE_NEW_CHECKOUT=false
147
+ ```
148
+
149
+ Validate environment variables at startup using a schema (Zod is ideal). Fail fast with a clear error message if required variables are missing or malformed. Never let the app silently run with bad configuration.
150
+
151
+ ### Avoiding the "Utils Dumping Ground"
152
+
153
+ A `utils/` directory with no sub-organization becomes a junk drawer within weeks. Apply the same discipline to utilities:
154
+
155
+ - Group by domain: `lib/date.ts`, `lib/currency.ts`, `lib/validation.ts`
156
+ - If a utility grows beyond ~100 lines, give it its own directory with an `index.ts`
157
+ - Delete utilities that are no longer used — dead code in `lib/` is worse than no code
158
+ - Never put business logic in `lib/`. Business logic belongs in features or hooks.
159
+
160
+ The test for whether something belongs in `lib/`: "Could I copy this to a different web app project without modification?" If yes, it belongs in `lib/`. If it has knowledge of this app's domain, it belongs in `features/` or `hooks/`.
@@ -0,0 +1,133 @@
1
+ ---
2
+ name: web-app-rendering-strategies
3
+ description: SSR TTFB and SEO benefits, SSG for content sites, ISR, streaming SSR, React Server Components, and progressive hydration patterns
4
+ topics: [web-app, rendering, ssr, ssg, isr, streaming, react-server-components, hydration]
5
+ ---
6
+
7
+ Rendering strategy is the foundational technical decision in a web app — it determines server infrastructure requirements, SEO characteristics, performance profile, and the developer model for data fetching. Understanding the precise mechanics of each strategy (not just their marketing descriptions) is essential for making and defending the right choice for a given project.
8
+
9
+ ## Summary
10
+
11
+ Rendering strategy determines server infrastructure, SEO characteristics, and performance profile. SSR provides SEO and fast LCP but adds server cost and TTFB. SSG gives sub-100ms TTFB from CDN but data is stale until rebuild. ISR extends SSG with per-route revalidation. Streaming SSR and React Server Components reduce bundle size and improve perceived performance by streaming content progressively. Most real-world apps need a hybrid approach.
12
+
13
+ ## Deep Guidance
14
+
15
+ ### SSR: Benefits and Real Costs
16
+
17
+ Server-Side Rendering generates HTML on the server for each request. The benefits are real but often overstated:
18
+
19
+ **Benefits:**
20
+ - **SEO**: Search engines receive pre-rendered HTML immediately. Critical for pages that must be indexed.
21
+ - **LCP on slow connections**: User sees content before JavaScript downloads and executes. Significant for mobile users on 3G.
22
+ - **Social sharing**: OG tags, Twitter Cards, and link previews work because the HTML is complete on the server response.
23
+ - **Auth-gated content**: Server can read session cookies and render personalized HTML without a client-side auth check causing layout flash.
24
+
25
+ **Real costs (often understated):**
26
+ - **TTFB**: Server must complete data fetching before sending the first byte. A slow database query delays the entire page. CSR serves a shell HTML in ~50 ms (CDN); SSR may take 200–500 ms for a database-backed page.
27
+ - **Server load**: Every page view consumes server CPU. At scale, this is a significant infrastructure cost vs. CDN-served static pages.
28
+ - **Caching complexity**: SSR responses may be personalized and cannot be cached at the CDN without careful `Vary` headers and cache key design.
29
+ - **Cold starts**: In serverless environments, SSR functions have cold start latency that static serving does not.
30
+
31
+ ### SSG: When It Is the Right Tool
32
+
33
+ Static Site Generation pre-builds every page at deploy time. It is the correct choice for:
34
+
35
+ - Content that changes at most a few times per day (blog, docs, marketing pages)
36
+ - Pages with no user-specific personalization in the HTML
37
+ - Maximum performance requirements (sub-100 ms TTFB from CDN)
38
+
39
+ SSG limitations are real and must be understood:
40
+ - **Build time**: Every page generates during CI. At 10,000 pages with 100 ms per page: 17 minutes of build time. Use incremental builds and build caching to mitigate.
41
+ - **Data freshness**: Pages are stale from the moment they are built. A product price change requires a rebuild to appear. Use on-demand revalidation (ISR) for this case.
42
+
43
+ ### ISR: Incremental Static Regeneration
44
+
45
+ ISR extends SSG with per-route revalidation intervals. A page marked `revalidate: 60` is served from the CDN static cache, but regenerated in the background every 60 seconds when a visitor triggers it:
46
+
47
+ - Stale-while-revalidate semantics: the first visitor after 60 seconds gets the old page; the next visitor gets the fresh page
48
+ - The regeneration happens server-side, not in response to a specific user — it is eventual consistency, not real-time
49
+ - On-demand ISR (via `res.revalidate(path)`) allows webhook-triggered immediate rebuilds — product price change → webhook → rebuild that product page within seconds
50
+
51
+ ISR is appropriate when "a few seconds to a minute stale" is acceptable and you want CDN-level performance without a full rebuild per data change.
52
+
53
+ ### Streaming SSR
54
+
55
+ React 18 and Next.js App Router support streaming HTML responses using `renderToPipeableStream` and `<Suspense>`:
56
+
57
+ 1. Server sends the page shell (header, navigation, above-fold layout) immediately — TTFB is fast
58
+ 2. Data-dependent sections are wrapped in `<Suspense>` with a fallback (skeleton)
59
+ 3. As each suspended section's data resolves, React streams its HTML directly into the response
60
+ 4. Browser progressively renders content as it arrives
61
+
62
+ This transforms LCP dramatically: users see layout and fast content immediately; slow data sections (product reviews, recommendations) arrive asynchronously without blocking the critical paint.
63
+
64
+ **Implementation pattern:**
65
+ ```tsx
66
+ // app/product/[id]/page.tsx
67
+ export default function ProductPage({ params }) {
68
+ return (
69
+ <main>
70
+ <ProductHero id={params.id} /> {/* Fast: renders immediately */}
71
+ <Suspense fallback={<ReviewSkeleton />}>
72
+ <ProductReviews id={params.id} /> {/* Slow: streams in when ready */}
73
+ </Suspense>
74
+ <Suspense fallback={<RecommendationSkeleton />}>
75
+ <Recommendations id={params.id} /> {/* Slow: streams in when ready */}
76
+ </Suspense>
77
+ </main>
78
+ );
79
+ }
80
+ ```
81
+
82
+ ### React Server Components
83
+
84
+ RSC is a model where components run exclusively on the server and send a serialized component description to the client — not HTML, not JavaScript:
85
+
86
+ - **Server Components**: Zero client-side JS. Read databases, file systems, environment variables directly. Not interactive.
87
+ - **Client Components**: Marked with `"use client"`. Run on both server (for initial HTML) and client (for interactivity). Receive server component output as props.
88
+ - **Benefit**: A product page with 40 KB of component code can ship 5 KB to the browser if most components are server-only.
89
+
90
+ The mental model shift: the client-server boundary is now drawn at the component level, not the page level. This is the most significant change in React architecture since hooks.
91
+
92
+ ### Choosing a Strategy: Decision Framework
93
+
94
+ Answer these questions in order:
95
+
96
+ 1. **Does this page need SEO?** If no → CSR. If yes → continue.
97
+ 2. **Is the content personalized per user?** If no → SSG or ISR. If yes → SSR or RSC.
98
+ 3. **How stale can the data be?** Minutes acceptable → ISR. Real-time required → SSR.
99
+ 4. **How much traffic?** Millions of pageviews/day → CDN-served (SSG/ISR) wins on cost. Low traffic → SSR is fine.
100
+
101
+ Most real-world apps need a hybrid: SSG for marketing, ISR for product listings, SSR for checkout, CSR for the user dashboard.
102
+
103
+ ### Progressive Hydration Pattern
104
+
105
+ In Next.js without RSC, implement progressive hydration by deferring non-critical component hydration:
106
+
107
+ ```typescript
108
+ import dynamic from "next/dynamic";
109
+
110
+ // Defer hydration until the component is in the viewport
111
+ const HeavyWidget = dynamic(() => import("./HeavyWidget"), {
112
+ ssr: false, // Not needed for SEO
113
+ loading: () => <WidgetSkeleton />,
114
+ });
115
+
116
+ // Or: load but don't hydrate until user interacts
117
+ const ChatWidget = dynamic(() => import("./ChatWidget"), {
118
+ ssr: false,
119
+ });
120
+ ```
121
+
122
+ Each dynamically imported component creates a separate JS chunk. Only load what is needed for the current page — analyze your bundle with `@next/bundle-analyzer` or `rollup-plugin-visualizer`.
123
+
124
+ ### Hydration Mismatch Debugging
125
+
126
+ The most common SSR debugging problem is hydration mismatches — the server renders different HTML than the client expects. Common causes:
127
+
128
+ - Browser-only APIs (`window`, `document`, `navigator`) accessed during server render
129
+ - Date formatting that differs between server timezone and client timezone
130
+ - Random values (`Math.random()`, `uuid()`) that differ between server and client renders
131
+ - Conditional rendering based on browser features (`typeof window !== 'undefined'`)
132
+
133
+ Fix by moving browser-only code into `useEffect` (runs only on client) or by using `dynamic(() => import(...), { ssr: false })` for components that inherently require the browser. Never suppress hydration warnings with `suppressHydrationWarning` except for timestamps and user-agent-dependent content where mismatch is expected and benign.
@@ -0,0 +1,112 @@
1
+ ---
2
+ name: web-app-requirements
3
+ description: SSR/SPA decision criteria, Core Web Vitals budgets, responsive breakpoints, browser support matrix, PWA considerations, and SEO requirements
4
+ topics: [web-app, requirements, performance, pwa, seo, accessibility]
5
+ ---
6
+
7
+ Defining web app requirements before writing a line of code prevents the most expensive rework in the project lifecycle. Rendering strategy, performance budgets, and browser support targets affect every architectural decision downstream. Locking these down early — with explicit tradeoff acknowledgment — removes ambiguity and gives the team a shared definition of "done."
8
+
9
+ ## Summary
10
+
11
+ Web app requirements establish rendering strategy (SSR for SEO, SPA for authenticated apps, hybrid for content-heavy sites), Core Web Vitals budgets (LCP < 2.5s, INP < 200ms, CLS < 0.1), responsive breakpoints from a shared token set, browser support matrix encoded via Browserslist, PWA scope decisions, and SEO requirements. Lock these down before sprint one.
12
+
13
+ ## Deep Guidance
14
+
15
+ ### SSR vs SPA Decision Criteria
16
+
17
+ Rendering strategy is the first architectural decision. The wrong choice costs weeks of retrofit:
18
+
19
+ - **Choose SSR (Next.js, Remix, SvelteKit, Nuxt)** when: SEO is critical (content sites, e-commerce, marketing), first-paint performance matters on slow connections, users are on low-powered devices, or content changes frequently and needs crawlability.
20
+ - **Choose SPA (React, Vue, Angular with CSR)** when: the app is behind authentication (no SEO need), interactions are highly dynamic (dashboards, tools, editors), and the user base is on capable hardware with fast connections.
21
+ - **Choose hybrid (SSG + client hydration)** when: most pages are static but some routes need real-time data. This is the default for most content-heavy sites — build pages at deploy time, hydrate interactive islands on the client.
22
+
23
+ Never choose SSR just because it is the current trend. Server rendering adds operational complexity (cold starts, caching headers, streaming), infrastructure cost, and harder debugging. Quantify the SEO and performance benefit before committing.
24
+
25
+ ### Core Web Vitals Budgets
26
+
27
+ Establish explicit targets before sprint one. These directly affect Google ranking and user conversion:
28
+
29
+ - **LCP (Largest Contentful Paint)**: Target under 2.5 seconds on a 3G mobile connection. Optimize with image preloads, font subsetting, and eliminating render-blocking resources.
30
+ - **FID / INP (Interaction to Next Paint)**: Target under 200 ms. Long JavaScript tasks block the main thread. Break up tasks, defer non-critical code, use Web Workers for heavy computation.
31
+ - **CLS (Cumulative Layout Shift)**: Target under 0.1. Reserve space for images and embeds. Avoid inserting content above the fold after initial paint.
32
+
33
+ Set budget alerts in Lighthouse CI on every PR. Treat regressions as build failures.
34
+
35
+ ### Responsive Breakpoints
36
+
37
+ Establish a breakpoint set and document it in the design system. A common mobile-first set:
38
+
39
+ - **Mobile**: base styles (320–767 px)
40
+ - **Tablet**: 768 px and up
41
+ - **Desktop**: 1024 px and up
42
+ - **Wide**: 1280 px and up (optional; cap content width at 1440 px to prevent excessive line length)
43
+
44
+ Do not invent per-component breakpoints. All breakpoints must come from a shared token set in CSS custom properties or a design token file.
45
+
46
+ ### Browser Support Matrix
47
+
48
+ Define this explicitly and commit it to the repo's `CONTRIBUTING.md` or a `BROWSERS.md` file:
49
+
50
+ - **Evergreen tier** (full support): Chrome, Edge, Firefox, Safari — last 2 major versions
51
+ - **Legacy tier** (functional, degraded): IE 11, Safari 12 — no graceful degradation unless business requires it
52
+ - **Mobile browsers**: Chrome for Android, Safari iOS — test on real devices, not just emulators
53
+
54
+ Use Browserslist to encode the matrix and share it across tools (Babel, PostCSS Autoprefixer, ESLint). Target: `"> 0.5%, last 2 versions, not dead"` as a safe default.
55
+
56
+ ### PWA Considerations
57
+
58
+ Decide at project start whether PWA features are required:
59
+
60
+ - **Service worker / offline**: Required if the app must function without connectivity or if mobile install is a goal. Adds complexity — cache invalidation is the #1 source of PWA bugs.
61
+ - **Web App Manifest**: Low cost, high value. Enables mobile home screen install and controls display mode. Add for any app targeting mobile users.
62
+ - **Push notifications**: Requires backend infrastructure and user permission flows. Scope carefully — most apps do not need this.
63
+
64
+ ### SEO Requirements
65
+
66
+ For public-facing apps:
67
+
68
+ - Server-render or statically generate all pages indexed by search engines. Client-rendered content is not reliably indexed.
69
+ - Implement `<title>`, `<meta description>`, Open Graph, and structured data (JSON-LD) on every route.
70
+ - Generate a sitemap at deploy time; submit to Google Search Console.
71
+ - Ensure canonical URLs, `robots.txt`, and proper handling of 404/301/302 responses.
72
+
73
+ ### Performance Budget Enforcement
74
+
75
+ Encode budgets in `budget.json` and enforce in CI:
76
+
77
+ ```json
78
+ {
79
+ "resourceSizes": [
80
+ { "resourceType": "script", "budget": 300 },
81
+ { "resourceType": "total", "budget": 1000 },
82
+ { "resourceType": "image", "budget": 500 }
83
+ ],
84
+ "timings": [
85
+ { "metric": "first-contentful-paint", "budget": 1500 },
86
+ { "metric": "interactive", "budget": 3500 },
87
+ { "metric": "largest-contentful-paint", "budget": 2500 }
88
+ ]
89
+ }
90
+ ```
91
+
92
+ Run `lighthouse-ci` on every PR against a representative page. Block merges that regress LCP, INP, or CLS beyond tolerance.
93
+
94
+ ### Defining "Supported" vs "Functional"
95
+
96
+ Do not conflate browser support tiers. Define what each means:
97
+
98
+ - **Supported**: All features work, tested in CI, regressions are P0 bugs.
99
+ - **Functional**: Core user journey works, advanced features may degrade gracefully.
100
+ - **Unsupported**: App may not load at all; display an upgrade notice.
101
+
102
+ Document which tier each browser falls into and socialize it with stakeholders before launch. Retrofitting support after launch is significantly more expensive than scoping it at project start.
103
+
104
+ ### Accessibility Requirements
105
+
106
+ Accessibility is a requirement, not a feature. Decide on the compliance target upfront:
107
+
108
+ - **WCAG 2.1 AA**: Industry baseline. Required for most government and enterprise customers.
109
+ - **WCAG 2.2 AA**: Current standard; prefer this for new projects.
110
+ - **Section 508**: Required for US federal contractors.
111
+
112
+ Automated tools (axe, Lighthouse) catch ~30–40% of issues. Manual keyboard navigation and screen reader testing (VoiceOver, NVDA) must supplement automation.