@zigrivers/scaffold 3.6.0 → 3.8.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 (115) hide show
  1. package/README.md +127 -12
  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/library/library-api-design.md +306 -0
  27. package/content/knowledge/library/library-architecture.md +247 -0
  28. package/content/knowledge/library/library-bundling.md +244 -0
  29. package/content/knowledge/library/library-conventions.md +229 -0
  30. package/content/knowledge/library/library-dev-environment.md +220 -0
  31. package/content/knowledge/library/library-documentation.md +300 -0
  32. package/content/knowledge/library/library-project-structure.md +237 -0
  33. package/content/knowledge/library/library-requirements.md +173 -0
  34. package/content/knowledge/library/library-security.md +257 -0
  35. package/content/knowledge/library/library-testing.md +319 -0
  36. package/content/knowledge/library/library-type-definitions.md +284 -0
  37. package/content/knowledge/library/library-versioning.md +300 -0
  38. package/content/knowledge/mobile-app/mobile-app-architecture.md +283 -0
  39. package/content/knowledge/mobile-app/mobile-app-conventions.md +180 -0
  40. package/content/knowledge/mobile-app/mobile-app-deployment.md +298 -0
  41. package/content/knowledge/mobile-app/mobile-app-dev-environment.md +257 -0
  42. package/content/knowledge/mobile-app/mobile-app-distribution.md +264 -0
  43. package/content/knowledge/mobile-app/mobile-app-observability.md +317 -0
  44. package/content/knowledge/mobile-app/mobile-app-offline-patterns.md +311 -0
  45. package/content/knowledge/mobile-app/mobile-app-project-structure.md +245 -0
  46. package/content/knowledge/mobile-app/mobile-app-push-notifications.md +321 -0
  47. package/content/knowledge/mobile-app/mobile-app-requirements.md +147 -0
  48. package/content/knowledge/mobile-app/mobile-app-security.md +338 -0
  49. package/content/knowledge/mobile-app/mobile-app-testing.md +400 -0
  50. package/content/knowledge/web-app/web-app-api-patterns.md +224 -0
  51. package/content/knowledge/web-app/web-app-architecture.md +116 -0
  52. package/content/knowledge/web-app/web-app-auth-patterns.md +256 -0
  53. package/content/knowledge/web-app/web-app-conventions.md +121 -0
  54. package/content/knowledge/web-app/web-app-data-patterns.md +218 -0
  55. package/content/knowledge/web-app/web-app-deployment-workflow.md +143 -0
  56. package/content/knowledge/web-app/web-app-deployment.md +134 -0
  57. package/content/knowledge/web-app/web-app-design-system.md +158 -0
  58. package/content/knowledge/web-app/web-app-dev-environment.md +173 -0
  59. package/content/knowledge/web-app/web-app-observability.md +221 -0
  60. package/content/knowledge/web-app/web-app-project-structure.md +160 -0
  61. package/content/knowledge/web-app/web-app-rendering-strategies.md +133 -0
  62. package/content/knowledge/web-app/web-app-requirements.md +112 -0
  63. package/content/knowledge/web-app/web-app-security.md +193 -0
  64. package/content/knowledge/web-app/web-app-session-patterns.md +214 -0
  65. package/content/knowledge/web-app/web-app-testing.md +249 -0
  66. package/content/knowledge/web-app/web-app-ux-patterns.md +162 -0
  67. package/content/methodology/backend-overlay.yml +73 -0
  68. package/content/methodology/cli-overlay.yml +69 -0
  69. package/content/methodology/library-overlay.yml +67 -0
  70. package/content/methodology/mobile-app-overlay.yml +71 -0
  71. package/content/methodology/web-app-overlay.yml +79 -0
  72. package/dist/cli/commands/init.d.ts +21 -0
  73. package/dist/cli/commands/init.d.ts.map +1 -1
  74. package/dist/cli/commands/init.js +261 -13
  75. package/dist/cli/commands/init.js.map +1 -1
  76. package/dist/cli/commands/init.test.js +206 -0
  77. package/dist/cli/commands/init.test.js.map +1 -1
  78. package/dist/config/schema.d.ts +1392 -64
  79. package/dist/config/schema.d.ts.map +1 -1
  80. package/dist/config/schema.js +82 -5
  81. package/dist/config/schema.js.map +1 -1
  82. package/dist/config/schema.test.js +302 -1
  83. package/dist/config/schema.test.js.map +1 -1
  84. package/dist/core/assembly/overlay-loader.d.ts.map +1 -1
  85. package/dist/core/assembly/overlay-loader.js +2 -1
  86. package/dist/core/assembly/overlay-loader.js.map +1 -1
  87. package/dist/core/assembly/overlay-loader.test.js +56 -0
  88. package/dist/core/assembly/overlay-loader.test.js.map +1 -1
  89. package/dist/e2e/game-pipeline.test.js +1 -0
  90. package/dist/e2e/game-pipeline.test.js.map +1 -1
  91. package/dist/e2e/project-type-overlays.test.d.ts +16 -0
  92. package/dist/e2e/project-type-overlays.test.d.ts.map +1 -0
  93. package/dist/e2e/project-type-overlays.test.js +834 -0
  94. package/dist/e2e/project-type-overlays.test.js.map +1 -0
  95. package/dist/types/config.d.ts +19 -2
  96. package/dist/types/config.d.ts.map +1 -1
  97. package/dist/types/index.d.ts +0 -1
  98. package/dist/types/index.d.ts.map +1 -1
  99. package/dist/types/index.js +0 -1
  100. package/dist/types/index.js.map +1 -1
  101. package/dist/wizard/questions.d.ts +27 -1
  102. package/dist/wizard/questions.d.ts.map +1 -1
  103. package/dist/wizard/questions.js +142 -3
  104. package/dist/wizard/questions.js.map +1 -1
  105. package/dist/wizard/questions.test.js +206 -8
  106. package/dist/wizard/questions.test.js.map +1 -1
  107. package/dist/wizard/wizard.d.ts +21 -0
  108. package/dist/wizard/wizard.d.ts.map +1 -1
  109. package/dist/wizard/wizard.js +27 -1
  110. package/dist/wizard/wizard.js.map +1 -1
  111. package/package.json +1 -1
  112. package/dist/types/wizard.d.ts +0 -14
  113. package/dist/types/wizard.d.ts.map +0 -1
  114. package/dist/types/wizard.js +0 -2
  115. package/dist/types/wizard.js.map +0 -1
@@ -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.
@@ -0,0 +1,193 @@
1
+ ---
2
+ name: web-app-security
3
+ description: XSS prevention, Content Security Policy, CSRF tokens, clickjacking, Subresource Integrity, dependency auditing, and OWASP top 10 for web apps
4
+ topics: [web-app, security, xss, csp, csrf, clickjacking, owasp, dependency-auditing]
5
+ ---
6
+
7
+ Web application security failures are among the most costly and common causes of data breaches. The OWASP Top 10 has catalogued the same categories of vulnerabilities for decades — not because they are new, but because they recur in every generation of frameworks and technologies. Understanding the attack vectors and their mitigations is not optional for engineers building user-facing web applications. Security must be designed in, not bolted on.
8
+
9
+ ## Summary
10
+
11
+ ### XSS (Cross-Site Scripting) Prevention
12
+
13
+ XSS occurs when attacker-controlled content is rendered as executable script in a victim's browser. It is the most prevalent web vulnerability class.
14
+
15
+ **Three XSS types:**
16
+ - **Stored XSS** — malicious script is stored in the database and rendered for all users (e.g., a comment containing `<script>`)
17
+ - **Reflected XSS** — malicious script is in the URL and reflected back in the response (e.g., a search page rendering the query parameter unsanitized)
18
+ - **DOM-based XSS** — malicious script is injected via client-side JavaScript manipulation of the DOM (e.g., `element.innerHTML = location.hash`)
19
+
20
+ **Primary defense: output encoding.** Modern React, Vue, and Angular frameworks automatically escape string interpolation. The vulnerabilities arise when developers bypass the framework: `dangerouslySetInnerHTML`, `v-html`, `innerHTML`, `document.write`, `eval()`.
21
+
22
+ **Content Security Policy (CSP):** A `Content-Security-Policy` response header instructs the browser to only execute scripts from trusted sources:
23
+
24
+ ```
25
+ Content-Security-Policy:
26
+ default-src 'self';
27
+ script-src 'self' https://trusted-cdn.com;
28
+ style-src 'self' 'unsafe-inline';
29
+ img-src 'self' data: https:;
30
+ font-src 'self' https://fonts.gstatic.com;
31
+ connect-src 'self' https://api.example.com;
32
+ frame-ancestors 'none';
33
+ upgrade-insecure-requests;
34
+ ```
35
+
36
+ `'unsafe-inline'` in `script-src` defeats the XSS protection benefit. Use nonces (`'nonce-{random}'`) or hashes instead for inline scripts.
37
+
38
+ ### Clickjacking Prevention
39
+
40
+ Clickjacking loads your application in a hidden `<iframe>` on an attacker's page. Users believe they are clicking on the attacker's UI but are actually clicking your application's buttons.
41
+
42
+ **Defense:** `Content-Security-Policy: frame-ancestors 'none'` (preferred) or the older `X-Frame-Options: DENY`. `frame-ancestors 'none'` prevents your app from being embedded in any frame. Use `frame-ancestors 'self'` if you need to allow same-origin framing.
43
+
44
+ ### CSRF Protection
45
+
46
+ Cross-Site Request Forgery tricks an authenticated user into submitting a request to your application from an attacker's site. The browser automatically sends cookies, making the forged request appear legitimate.
47
+
48
+ **Primary defense:** `SameSite=Strict` or `SameSite=Lax` cookies. With `SameSite=Strict`, the cookie is never sent on cross-site requests, making CSRF impossible.
49
+
50
+ **Secondary defense for legacy or cross-site scenarios:** Synchronizer token pattern — include a CSRF token in every form/request and validate it on the server.
51
+
52
+ ### Subresource Integrity (SRI)
53
+
54
+ When loading scripts or stylesheets from CDNs, SRI prevents a compromised CDN from serving malicious content:
55
+
56
+ ```html
57
+ <script
58
+ src="https://cdn.example.com/library.min.js"
59
+ integrity="sha384-oqVuAfXRKap7fdgcCY5uykM6+R9GqQ8K/ux8P/C5b2E8x2U6sQ=="
60
+ crossorigin="anonymous"
61
+ ></script>
62
+ ```
63
+
64
+ The browser verifies the hash of the loaded resource. If it does not match, the resource is blocked. Generate hashes with: `openssl dgst -sha384 -binary file.js | openssl base64 -A`.
65
+
66
+ ### Dependency Auditing
67
+
68
+ Third-party dependencies are the most underestimated attack surface. The 2021 Log4Shell vulnerability and 2022 node-ipc supply chain attack demonstrated that a dependency in a dependency can cause a critical vulnerability.
69
+
70
+ **Baseline practices:**
71
+ - Run `npm audit` or `pnpm audit` in CI — fail the build on critical/high severities
72
+ - Pin exact dependency versions in production builds (lockfile required)
73
+ - Review dependency additions as carefully as code additions
74
+ - Subscribe to security advisories for critical dependencies (GitHub Dependabot, Snyk)
75
+
76
+ ## Deep Guidance
77
+
78
+ ### Content Security Policy Implementation
79
+
80
+ Deploying CSP in production requires a staged approach — a strict policy will break things:
81
+
82
+ **Phase 1: Report-only mode.** Use `Content-Security-Policy-Report-Only` with a `report-uri` endpoint. This logs violations without blocking anything. Collect violations for 1–2 weeks.
83
+
84
+ **Phase 2: Fix violations.** Address inline scripts (move to external files or use nonces), fix disallowed origins, and handle third-party widget requirements.
85
+
86
+ **Phase 3: Enforce.** Switch to `Content-Security-Policy`. Monitor violation reports for regressions.
87
+
88
+ ```typescript
89
+ // Next.js CSP with nonces (recommended over 'unsafe-inline')
90
+ import { headers } from 'next/headers';
91
+ import crypto from 'crypto';
92
+
93
+ export default function RootLayout({ children }) {
94
+ const nonce = crypto.randomBytes(16).toString('base64');
95
+
96
+ const cspHeader = [
97
+ `default-src 'self'`,
98
+ `script-src 'self' 'nonce-${nonce}' 'strict-dynamic'`,
99
+ `style-src 'self' 'nonce-${nonce}'`,
100
+ `img-src 'self' blob: data: https:`,
101
+ `font-src 'self'`,
102
+ `object-src 'none'`,
103
+ `base-uri 'self'`,
104
+ `form-action 'self'`,
105
+ `frame-ancestors 'none'`,
106
+ `upgrade-insecure-requests`,
107
+ ].join('; ');
108
+
109
+ return (
110
+ <html>
111
+ <head>
112
+ <meta httpEquiv="Content-Security-Policy" content={cspHeader} />
113
+ </head>
114
+ <body>{children}</body>
115
+ </html>
116
+ );
117
+ }
118
+ ```
119
+
120
+ ### Security Headers Checklist
121
+
122
+ Every production web app must serve these response headers:
123
+
124
+ ```
125
+ # Prevent clickjacking
126
+ Content-Security-Policy: frame-ancestors 'none'
127
+ X-Frame-Options: DENY # Legacy browsers
128
+
129
+ # Prevent MIME sniffing
130
+ X-Content-Type-Options: nosniff
131
+
132
+ # Enable HSTS (HTTP Strict Transport Security)
133
+ Strict-Transport-Security: max-age=63072000; includeSubDomains; preload
134
+
135
+ # Control referrer information
136
+ Referrer-Policy: strict-origin-when-cross-origin
137
+
138
+ # Control browser features
139
+ Permissions-Policy: camera=(), microphone=(), geolocation=()
140
+
141
+ # Prevent IE compatibility mode
142
+ X-UA-Compatible: IE=edge
143
+ ```
144
+
145
+ Configure these in your CDN (Cloudflare, Vercel, Fastly) or reverse proxy rather than application code — they should apply to all responses including static assets.
146
+
147
+ ### HTML Sanitization for User Content
148
+
149
+ When you must render user-supplied HTML (rich text editors, markdown with HTML), use a server-side sanitization library:
150
+
151
+ ```typescript
152
+ import DOMPurify from 'isomorphic-dompurify';
153
+
154
+ // GOOD: Sanitize before storage and before rendering
155
+ function sanitizeUserHTML(html: string): string {
156
+ return DOMPurify.sanitize(html, {
157
+ ALLOWED_TAGS: ['p', 'strong', 'em', 'ul', 'ol', 'li', 'a', 'br', 'blockquote'],
158
+ ALLOWED_ATTR: ['href', 'target', 'rel'],
159
+ FORBID_ATTR: ['style', 'class', 'id'],
160
+ ADD_ATTR: ['rel'], // Ensure all links have rel="noopener noreferrer"
161
+ FORCE_BODY: true,
162
+ });
163
+ }
164
+
165
+ // BAD: Rendering user HTML without sanitization
166
+ function UnsafeComponent({ userContent }) {
167
+ return <div dangerouslySetInnerHTML={{ __html: userContent }} />; // XSS risk
168
+ }
169
+
170
+ // GOOD: Sanitize before rendering
171
+ function SafeComponent({ userContent }) {
172
+ return <div dangerouslySetInnerHTML={{ __html: sanitizeUserHTML(userContent) }} />;
173
+ }
174
+ ```
175
+
176
+ **Always add `rel="noopener noreferrer"` to user-supplied links.** Without `noopener`, the linked page can access `window.opener` and redirect the original tab.
177
+
178
+ ### OWASP Top 10 Mapping
179
+
180
+ | OWASP 2021 | Web App Mitigation |
181
+ |---|---|
182
+ | A01 Broken Access Control | Server-side authz on every endpoint; never trust client-claimed identity |
183
+ | A02 Cryptographic Failures | TLS everywhere; never store passwords in plaintext; use bcrypt/Argon2 |
184
+ | A03 Injection | Parameterized queries; ORM; never concatenate user input into SQL/shell commands |
185
+ | A04 Insecure Design | Threat model before building auth/payment flows |
186
+ | A05 Security Misconfiguration | Headers checklist; disable debug endpoints in production; rotate default credentials |
187
+ | A06 Vulnerable Components | `npm audit` in CI; Dependabot alerts; pin lockfile |
188
+ | A07 Auth Failures | PKCE; rate limiting on login; MFA; session timeout |
189
+ | A08 Software Integrity | SRI for CDN assets; verify npm package checksums; signed commits |
190
+ | A09 Logging Failures | Log auth events; alert on anomalies; never log passwords or tokens |
191
+ | A10 SSRF | Validate and restrict URLs in server-side fetch calls; block private IP ranges |
192
+
193
+ Run a security review against this checklist before the first production deployment and after any major auth or data flow change.
@@ -0,0 +1,214 @@
1
+ ---
2
+ name: web-app-session-patterns
3
+ description: Session management architecture, JWT vs cookie sessions, refresh token rotation, session storage, and hijacking prevention
4
+ topics: [web-app, auth, sessions, jwt, cookies, security, redis]
5
+ ---
6
+
7
+ Session management is the mechanism by which a web application recognizes a returning user between HTTP requests. Because HTTP is stateless, sessions are an application-level construct — and the design decisions here directly affect security, scalability, and user experience. The wrong session architecture causes token theft, session fixation attacks, memory exhaustion on the server, and logout failures that leave users permanently authenticated even after they believe they've signed out.
8
+
9
+ ## Summary
10
+
11
+ ### JWT vs Cookie Sessions
12
+
13
+ The two primary session patterns have fundamentally different security models:
14
+
15
+ **Cookie-based sessions (server-authoritative):**
16
+ - Server stores session state (database or Redis); client holds an opaque session ID in a cookie
17
+ - Immediate revocation: delete the session record and the user is logged out
18
+ - Scales horizontally when session storage is centralized (Redis cluster)
19
+ - HttpOnly + Secure + SameSite=Strict cookies resist XSS and CSRF simultaneously
20
+ - Each request requires a session store lookup — adds latency (~1–5 ms for Redis)
21
+
22
+ **JWT (stateless):**
23
+ - Server stores no session state; the signed token is the complete session
24
+ - No revocation without a token denylist (which re-introduces statefulness)
25
+ - Zero session store lookups per request — appropriate for stateless microservices
26
+ - Tokens can be stolen and reused until expiry — short expiry (15 minutes) is essential
27
+ - Refresh tokens enable long sessions without long-lived access tokens
28
+
29
+ **Rule of thumb:** Use cookie-based sessions for user-facing web apps where revocation matters. Use JWTs for service-to-service auth or APIs where clients are trusted and revocation is not required. Hybrid: short-lived JWTs + server-side refresh token rotation is the most common production pattern.
30
+
31
+ ### Refresh Token Rotation
32
+
33
+ Refresh token rotation is the critical security mechanism for long-lived JWT sessions:
34
+
35
+ 1. Access token expires in 15 minutes
36
+ 2. Client uses refresh token to obtain a new access token + new refresh token
37
+ 3. The old refresh token is immediately invalidated
38
+ 4. If the old refresh token is ever presented again, all sessions for that user are terminated (token reuse detection indicates theft)
39
+
40
+ This pattern detects token theft: if an attacker steals a refresh token and uses it, the legitimate user's next refresh attempt will fail and force re-authentication, alerting the user and invalidating the attacker's session.
41
+
42
+ ### Session Storage Backends
43
+
44
+ | Backend | Best For | Limits |
45
+ |---|---|---|
46
+ | Redis (single node) | Fast sessions, moderate scale | Single point of failure |
47
+ | Redis Cluster | High availability, large scale | Operational complexity |
48
+ | Redis Sentinel | Automatic failover for single-node Redis | Less scale than Cluster |
49
+ | Database (PostgreSQL) | Simpler stack, queryable sessions | Higher latency than Redis |
50
+ | In-process memory | Development only | Lost on restart, no horizontal scale |
51
+
52
+ For production, Redis is the standard choice: sub-millisecond lookups, TTL-based expiry is native, and session invalidation is an O(1) DEL command.
53
+
54
+ ### Token Expiry Strategy
55
+
56
+ Define expiry per token type based on risk tolerance:
57
+
58
+ - **Access token**: 15 minutes — short enough to limit exposure if stolen
59
+ - **Refresh token**: 7–30 days — rotate on each use; invalidate on logout
60
+ - **Remember-me token**: 90 days — separate from standard refresh, requires stronger audit
61
+ - **Email verification token**: 24–48 hours — single-use, invalidate on consumption
62
+ - **Password reset token**: 1 hour — single-use, invalidate on consumption, invalidate all sessions on use
63
+
64
+ ## Deep Guidance
65
+
66
+ ### Secure Cookie Configuration
67
+
68
+ Every session cookie must be configured with all three security attributes:
69
+
70
+ ```typescript
71
+ // Express.js session cookie configuration
72
+ app.use(session({
73
+ name: '__Host-sessionId', // __Host- prefix requires Secure + path=/ + no domain
74
+ secret: process.env.SESSION_SECRET,
75
+ resave: false,
76
+ saveUninitialized: false,
77
+ cookie: {
78
+ httpOnly: true, // Inaccessible to JavaScript — prevents XSS token theft
79
+ secure: true, // HTTPS only — prevents transmission over HTTP
80
+ sameSite: 'strict', // Not sent on cross-site requests — prevents CSRF
81
+ maxAge: 7 * 24 * 60 * 60 * 1000, // 7 days in milliseconds
82
+ path: '/',
83
+ },
84
+ store: new RedisStore({ client: redisClient }),
85
+ }));
86
+ ```
87
+
88
+ The `__Host-` cookie name prefix is a browser-enforced security policy that prevents subdomain hijacking — it requires `Secure`, `path=/`, and no `Domain` attribute. Use it for session cookies in production.
89
+
90
+ ### Refresh Token Rotation Implementation
91
+
92
+ ```typescript
93
+ interface TokenPair {
94
+ accessToken: string;
95
+ refreshToken: string;
96
+ accessTokenExpiresAt: Date;
97
+ }
98
+
99
+ async function rotateRefreshToken(
100
+ incomingRefreshToken: string
101
+ ): Promise<TokenPair> {
102
+ // 1. Look up the incoming refresh token
103
+ const storedToken = await db.refreshToken.findUnique({
104
+ where: { token: incomingRefreshToken },
105
+ include: { user: true },
106
+ });
107
+
108
+ if (!storedToken) {
109
+ // Token not found — could be expired, already rotated, or forged
110
+ throw new AuthError('INVALID_REFRESH_TOKEN');
111
+ }
112
+
113
+ if (storedToken.usedAt !== null) {
114
+ // REUSE DETECTED: token was already rotated — potential theft
115
+ // Invalidate ALL refresh tokens for this user
116
+ await db.refreshToken.updateMany({
117
+ where: { userId: storedToken.userId },
118
+ data: { revokedAt: new Date() },
119
+ });
120
+ throw new AuthError('TOKEN_REUSE_DETECTED');
121
+ }
122
+
123
+ if (storedToken.revokedAt !== null || storedToken.expiresAt < new Date()) {
124
+ throw new AuthError('REFRESH_TOKEN_EXPIRED');
125
+ }
126
+
127
+ // 2. Mark old token as used (not deleted — needed for reuse detection)
128
+ await db.refreshToken.update({
129
+ where: { id: storedToken.id },
130
+ data: { usedAt: new Date() },
131
+ });
132
+
133
+ // 3. Issue new token pair
134
+ const newAccessToken = signAccessToken({ sub: storedToken.userId });
135
+ const newRefreshToken = await db.refreshToken.create({
136
+ data: {
137
+ userId: storedToken.userId,
138
+ token: generateSecureToken(),
139
+ expiresAt: addDays(new Date(), 30),
140
+ parentTokenId: storedToken.id, // Track rotation chain
141
+ },
142
+ });
143
+
144
+ return {
145
+ accessToken: newAccessToken,
146
+ refreshToken: newRefreshToken.token,
147
+ accessTokenExpiresAt: addMinutes(new Date(), 15),
148
+ };
149
+ }
150
+ ```
151
+
152
+ ### Session Hijacking Prevention
153
+
154
+ Beyond secure cookies, defend against session hijacking at the application layer:
155
+
156
+ **IP binding (optional, use carefully):**
157
+ - Store the client IP at session creation and validate on each request
158
+ - Breaks for legitimate users on mobile networks (IP changes per cell tower)
159
+ - Use only for high-security flows (admin panels, bank-grade apps), not general user sessions
160
+
161
+ **User-Agent fingerprint:**
162
+ - Store a hash of the User-Agent string at session creation
163
+ - Validate on each request; suspicious changes invalidate the session
164
+ - Not a strong defense (UA is spoofable) but raises the cost of attack
165
+
166
+ **Session fixation prevention:**
167
+ - Always regenerate the session ID on successful authentication
168
+ - Never allow the session ID to be set via URL parameters (cookie-only)
169
+ - In Express: call `req.session.regenerate()` after successful login
170
+
171
+ **Concurrent session limits:**
172
+ - Track active session count per user in Redis
173
+ - On new login, offer the user the choice to log out other sessions or enforce a maximum
174
+ - Essential for compliance in regulated industries
175
+
176
+ ### Redis Session Store with TTL
177
+
178
+ ```typescript
179
+ import Redis from 'ioredis';
180
+ import RedisStore from 'connect-redis';
181
+
182
+ const redisClient = new Redis({
183
+ host: process.env.REDIS_HOST,
184
+ port: 6379,
185
+ // Lazy connect — don't block startup if Redis is temporarily unavailable
186
+ lazyConnect: true,
187
+ // Retry strategy — exponential backoff
188
+ retryStrategy: (times: number) => Math.min(times * 50, 2000),
189
+ });
190
+
191
+ // Sessions expire automatically via Redis TTL — no cleanup job needed
192
+ const sessionStore = new RedisStore({
193
+ client: redisClient,
194
+ prefix: 'sess:',
195
+ ttl: 7 * 24 * 60 * 60, // 7 days in seconds
196
+ });
197
+
198
+ // Invalidate a specific session (logout)
199
+ async function invalidateSession(sessionId: string): Promise<void> {
200
+ await redisClient.del(`sess:${sessionId}`);
201
+ }
202
+
203
+ // Invalidate all sessions for a user (force logout everywhere)
204
+ async function invalidateAllUserSessions(userId: string): Promise<void> {
205
+ // Requires storing a user→sessions index in Redis
206
+ const sessionIds = await redisClient.smembers(`user:sessions:${userId}`);
207
+ if (sessionIds.length > 0) {
208
+ await redisClient.del(...sessionIds.map(id => `sess:${id}`));
209
+ await redisClient.del(`user:sessions:${userId}`);
210
+ }
211
+ }
212
+ ```
213
+
214
+ Maintain a `user:sessions:{userId}` Redis set to enable "logout everywhere" — essential for security incident response.