@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,218 @@
1
+ ---
2
+ name: web-app-data-patterns
3
+ description: Client-side caching, optimistic updates, real-time sync, pagination strategies, form state management, and file upload patterns
4
+ topics: [web-app, data-fetching, caching, react-query, swr, pagination, forms, file-upload]
5
+ ---
6
+
7
+ Data management in web applications spans from simple fetch-and-display to complex real-time collaborative state. The wrong patterns here produce stale UIs, conflicting updates, degraded performance under load, and frustrated users. The right patterns make applications feel instantaneous even over slow networks — by understanding the difference between server state, client state, and ephemeral UI state, and applying the appropriate tool to each.
8
+
9
+ ## Summary
10
+
11
+ ### Server State vs Client State
12
+
13
+ The most important conceptual distinction in modern web data management:
14
+
15
+ - **Server state** — data owned by the server, shared across clients, and potentially stale as soon as it's fetched: user profiles, product listings, feed items. Use a data-fetching library (React Query, SWR) to manage this.
16
+ - **Client state** — data owned by the current user's session, not persisted to the server: currently selected tab, sidebar open/closed, in-progress form data. Use React local state or Zustand/Jotai/Redux.
17
+
18
+ Mixing these causes anti-patterns: putting server data in Redux, or making API calls from useEffect without caching. Libraries like React Query exist precisely because server state needs cache management, background refetching, deduplication, and stale-while-revalidate semantics that generic state managers don't provide.
19
+
20
+ ### SWR vs React Query
21
+
22
+ Both implement stale-while-revalidate caching for server state:
23
+
24
+ | Concern | SWR | React Query (TanStack Query) |
25
+ |---|---|---|
26
+ | Bundle size | ~6 KB | ~13 KB |
27
+ | Mutations | Manual invalidation | Built-in `useMutation` + auto-invalidation |
28
+ | Infinite scroll | `useSWRInfinite` | `useInfiniteQuery` |
29
+ | Optimistic updates | Manual | First-class via `onMutate` + rollback |
30
+ | DevTools | None built-in | Excellent DevTools panel |
31
+ | Best for | Read-heavy apps, minimal mutations | Apps with complex mutation flows |
32
+
33
+ **Rule:** Use React Query for most production applications. Use SWR for read-heavy dashboards where its simplicity is a net benefit.
34
+
35
+ ### Optimistic Updates
36
+
37
+ Update the UI before the server confirms the mutation. If the server rejects, roll back.
38
+
39
+ Optimistic updates are appropriate when: the mutation has a very high success rate, the latency is noticeable, and the rollback experience is not confusing. They are not appropriate when: the server-side result is unpredictable (e.g., a bid on an auction where you may lose).
40
+
41
+ ### Pagination Strategies
42
+
43
+ **Cursor-based pagination** (preferred):
44
+ - Each page returns a `nextCursor` opaque token; the next request passes `?cursor=<token>`
45
+ - Stable across concurrent inserts/deletes — no items skipped or duplicated
46
+ - Required for infinite scroll (offset pagination breaks on live data)
47
+ - Cannot jump to arbitrary page numbers
48
+
49
+ **Offset-based pagination**:
50
+ - `?page=3&limit=20` or `?offset=40&limit=20`
51
+ - Supports "jump to page N" UI
52
+ - Items shift when rows are inserted/deleted — users see duplicates or skipped items on live data
53
+ - Appropriate for admin tables with infrequent writes and explicit page navigation
54
+
55
+ ### Real-Time Data Sync
56
+
57
+ Three patterns in increasing complexity:
58
+ 1. **Polling** — simplest, least efficient: re-fetch every N seconds. Acceptable for dashboards that update every few minutes.
59
+ 2. **Server-Sent Events (SSE)** — server pushes updates to client over a single long-lived HTTP connection. One-directional. Excellent for notifications, activity feeds, live counters. No WebSocket negotiation overhead.
60
+ 3. **WebSocket** — bidirectional full-duplex. Required for chat, collaborative editing, live games. Higher complexity: connection management, reconnection, presence.
61
+
62
+ ## Deep Guidance
63
+
64
+ ### React Query Patterns
65
+
66
+ ```typescript
67
+ // 1. Standard query with stale time
68
+ const { data: posts, isLoading, error } = useQuery({
69
+ queryKey: ['posts', { authorId, page }],
70
+ queryFn: () => fetchPosts({ authorId, page }),
71
+ staleTime: 5 * 60 * 1000, // Data considered fresh for 5 minutes
72
+ gcTime: 10 * 60 * 1000, // Keep in cache for 10 minutes after unmount
73
+ });
74
+
75
+ // 2. Optimistic mutation with rollback
76
+ const queryClient = useQueryClient();
77
+
78
+ const likeMutation = useMutation({
79
+ mutationFn: (postId: string) => api.likePost(postId),
80
+
81
+ onMutate: async (postId) => {
82
+ // Cancel any in-flight refetches that would overwrite optimistic update
83
+ await queryClient.cancelQueries({ queryKey: ['posts'] });
84
+
85
+ // Snapshot the previous value
86
+ const previousPosts = queryClient.getQueryData(['posts']);
87
+
88
+ // Optimistically update
89
+ queryClient.setQueryData(['posts'], (old: Post[]) =>
90
+ old.map(p => p.id === postId ? { ...p, likeCount: p.likeCount + 1, likedByMe: true } : p)
91
+ );
92
+
93
+ // Return context for rollback
94
+ return { previousPosts };
95
+ },
96
+
97
+ onError: (error, postId, context) => {
98
+ // Roll back to snapshot on failure
99
+ queryClient.setQueryData(['posts'], context?.previousPosts);
100
+ },
101
+
102
+ onSettled: () => {
103
+ // Always refetch to sync with server truth
104
+ queryClient.invalidateQueries({ queryKey: ['posts'] });
105
+ },
106
+ });
107
+
108
+ // 3. Infinite scroll
109
+ const { data, fetchNextPage, hasNextPage, isFetchingNextPage } = useInfiniteQuery({
110
+ queryKey: ['feed'],
111
+ queryFn: ({ pageParam }) => fetchFeed({ cursor: pageParam }),
112
+ getNextPageParam: (lastPage) => lastPage.nextCursor ?? undefined,
113
+ initialPageParam: undefined as string | undefined,
114
+ });
115
+ ```
116
+
117
+ ### File Upload Pattern
118
+
119
+ Uploads require a different flow from standard JSON mutations: multipart form data, progress tracking, and (for large files) direct-to-storage upload via presigned URLs.
120
+
121
+ ```typescript
122
+ // PATTERN: Presigned URL upload (bypasses app server, goes direct to S3/GCS)
123
+ async function uploadFile(file: File, onProgress: (pct: number) => void) {
124
+ // Step 1: Get presigned URL from app server
125
+ const { uploadUrl, fileKey } = await api.getUploadUrl({
126
+ filename: file.name,
127
+ contentType: file.type,
128
+ size: file.size,
129
+ });
130
+
131
+ // Step 2: Upload directly to storage (no app server in the critical path)
132
+ await new Promise<void>((resolve, reject) => {
133
+ const xhr = new XMLHttpRequest();
134
+ xhr.open('PUT', uploadUrl);
135
+ xhr.setRequestHeader('Content-Type', file.type);
136
+
137
+ xhr.upload.onprogress = (event) => {
138
+ if (event.lengthComputable) {
139
+ onProgress(Math.round((event.loaded / event.total) * 100));
140
+ }
141
+ };
142
+
143
+ xhr.onload = () => xhr.status === 200 ? resolve() : reject(new Error(`Upload failed: ${xhr.status}`));
144
+ xhr.onerror = () => reject(new Error('Network error during upload'));
145
+ xhr.send(file);
146
+ });
147
+
148
+ // Step 3: Notify app server that upload is complete
149
+ return api.confirmUpload({ fileKey });
150
+ }
151
+ ```
152
+
153
+ Presigned URL uploads: never proxy large files through your app server. A 100 MB upload through an app server occupies a Node.js worker for the entire transfer duration.
154
+
155
+ ### Form State Management
156
+
157
+ For most forms: `react-hook-form` + Zod schema validation. This pattern avoids controlled component re-renders (critical for large forms), provides schema-driven validation, and integrates cleanly with TypeScript.
158
+
159
+ ```typescript
160
+ import { useForm } from 'react-hook-form';
161
+ import { zodResolver } from '@hookform/resolvers/zod';
162
+ import { z } from 'zod';
163
+
164
+ const profileSchema = z.object({
165
+ displayName: z.string().min(2).max(50),
166
+ email: z.string().email(),
167
+ bio: z.string().max(500).optional(),
168
+ });
169
+
170
+ type ProfileForm = z.infer<typeof profileSchema>;
171
+
172
+ function ProfileEditor() {
173
+ const { register, handleSubmit, formState: { errors, isDirty, isSubmitting } } = useForm<ProfileForm>({
174
+ resolver: zodResolver(profileSchema),
175
+ defaultValues: { displayName: user.displayName, email: user.email },
176
+ });
177
+
178
+ const onSubmit = async (data: ProfileForm) => {
179
+ await updateProfile(data);
180
+ };
181
+
182
+ return (
183
+ <form onSubmit={handleSubmit(onSubmit)}>
184
+ <input {...register('displayName')} />
185
+ {errors.displayName && <span>{errors.displayName.message}</span>}
186
+ <button type="submit" disabled={!isDirty || isSubmitting}>Save</button>
187
+ </form>
188
+ );
189
+ }
190
+ ```
191
+
192
+ Reserve heavier solutions (Formik, final-form) only for highly dynamic form generation requirements. For most product forms, react-hook-form is sufficient and faster.
193
+
194
+ ### Cursor Pagination Implementation
195
+
196
+ ```typescript
197
+ // Server-side cursor pagination (PostgreSQL + Prisma)
198
+ async function getPaginatedPosts(cursor?: string, limit = 20) {
199
+ const posts = await prisma.post.findMany({
200
+ take: limit + 1, // Fetch one extra to determine if there's a next page
201
+ ...(cursor && {
202
+ cursor: { id: cursor },
203
+ skip: 1, // Skip the cursor item itself
204
+ }),
205
+ orderBy: { createdAt: 'desc' },
206
+ });
207
+
208
+ const hasNextPage = posts.length > limit;
209
+ const items = hasNextPage ? posts.slice(0, -1) : posts;
210
+
211
+ return {
212
+ items,
213
+ nextCursor: hasNextPage ? items[items.length - 1].id : null,
214
+ };
215
+ }
216
+ ```
217
+
218
+ Always fetch `limit + 1` to check for next page existence without an extra COUNT query.
@@ -0,0 +1,143 @@
1
+ ---
2
+ name: web-app-deployment-workflow
3
+ description: Preview deploys per PR, staging environments, deployment branches, CI/CD pipeline stages, rollback strategies, and canary deployments
4
+ topics: [web-app, deployment, ci-cd, staging, preview, rollback, canary]
5
+ ---
6
+
7
+ A mature deployment workflow transforms deployment from a risky, manual event into a routine, automated step. The goal is to make every merge to main automatically and safely deliverable to production, with fast rollback when something goes wrong. The cost of building this infrastructure up front is trivially small compared to the cost of a major incident caused by a manual deploy process.
8
+
9
+ ## Summary
10
+
11
+ A mature deployment workflow makes every merge to main automatically deliverable with fast rollback. Every PR gets a preview deploy. CI/CD runs lint, typecheck, test, and build in fail-fast order. Test rollback procedures quarterly. For high-traffic apps, use canary deployments with explicit rollback criteria.
12
+
13
+ ## Deep Guidance
14
+
15
+ ### Preview Deploys Per PR
16
+
17
+ Every pull request should get its own preview deployment — a fully functional URL that reviewers and QA can use to verify behavior before merging. This is the single highest-ROI practice in modern web deployment:
18
+
19
+ - **Vercel, Netlify, Railway**: Automatically create preview deploys on PR open/push. Zero configuration for most frameworks.
20
+ - **Custom CI**: Build and deploy to a path-based preview URL (`preview/<pr-number>/`) or a subdomain. Tear down on PR close.
21
+
22
+ Preview deploys must use isolated environment variables (dev database, dev third-party API keys). Never point a preview deploy at a production database.
23
+
24
+ ### Deployment Branches
25
+
26
+ Establish a clear branch-to-environment mapping and document it in the repo:
27
+
28
+ | Branch | Environment | Deploys |
29
+ |--------|-------------|---------|
30
+ | `main` | Production | Automatic on merge |
31
+ | `staging` | Staging | Automatic on merge |
32
+ | `feature/*`, `fix/*` | Preview | Automatic on PR push |
33
+
34
+ Avoid long-lived branches other than `main` and optionally `staging`. Feature branches merge to `main` via PR. `main` deploys to production. This is the simplest model that works.
35
+
36
+ If you have a separate `staging` branch: keep it in sync with `main` via regular merges. Staging branches that lag `main` by weeks create false confidence and painful integration surprises.
37
+
38
+ ### CI/CD Pipeline Stages
39
+
40
+ Every push to a branch should run a pipeline in this order (fast-to-slow, fail-fast):
41
+
42
+ 1. **Install dependencies** (cached; skip if lockfile unchanged)
43
+ 2. **Lint** — ESLint, Prettier check (fail fast; ~30 seconds)
44
+ 3. **Typecheck** — `tsc --noEmit` (fail fast; ~60 seconds)
45
+ 4. **Unit tests** — Vitest/Jest with coverage threshold (1–3 minutes)
46
+ 5. **Build** — Production build to verify no build errors (2–5 minutes)
47
+ 6. **E2E tests** (optional, on main/staging only) — Playwright or Cypress against preview deploy (5–15 minutes)
48
+ 7. **Deploy** — Only if all above pass
49
+
50
+ Do not run all tests on every PR if the test suite is slow. Use test impact analysis (run only tests related to changed files) or split E2E tests to a separate workflow that runs on merge to `main`.
51
+
52
+ ### Rollback Strategies
53
+
54
+ Every deployment system must have a tested rollback procedure. "We can just revert the commit and redeploy" is not a rollback strategy — that takes 5+ minutes and requires a developer to execute it under pressure.
55
+
56
+ - **Vercel/Netlify**: One-click rollback to any previous deployment in the dashboard. Target: under 30 seconds to rollback.
57
+ - **Custom infrastructure**: Maintain the previous two deployment artifacts. Rollback = swap the active artifact. Use blue-green or immutable deployment patterns (see below).
58
+ - **Database migrations**: Rollback is the hard part. Write migrations that are forward-compatible (additive only). Keep destructive changes separate, deployed only after the new code is stable. Use a migration tool that tracks state (Prisma, Flyway, Liquibase).
59
+
60
+ Test the rollback procedure at least quarterly. A rollback you have never practiced will fail in an incident.
61
+
62
+ ### Canary Deployments
63
+
64
+ For high-traffic production apps, deploy changes to a small percentage of traffic before full rollout:
65
+
66
+ - Route 5% of requests to the new version, 95% to the old
67
+ - Monitor error rates, latency, and business metrics for 15–30 minutes
68
+ - Gradually increase the percentage or roll back if metrics degrade
69
+
70
+ Canary deployments require infrastructure support: feature flag services (LaunchDarkly, Unleash), traffic splitting at the load balancer (AWS ALB weighted routing, Cloudflare Workers), or platform-level support (Vercel edge middleware). Do not implement canaries manually — use the platform's built-in mechanism.
71
+
72
+ ### CI/CD Pipeline Template (GitHub Actions)
73
+
74
+ ```yaml
75
+ # .github/workflows/ci.yml
76
+ name: CI
77
+
78
+ on:
79
+ push:
80
+ branches: [main, staging]
81
+ pull_request:
82
+
83
+ jobs:
84
+ quality:
85
+ runs-on: ubuntu-latest
86
+ steps:
87
+ - uses: actions/checkout@v4
88
+ - uses: actions/setup-node@v4
89
+ with:
90
+ node-version: 20
91
+ cache: npm
92
+ - run: npm ci
93
+ - run: npm run lint
94
+ - run: npm run typecheck
95
+ - run: npm run test -- --coverage
96
+ - run: npm run build
97
+
98
+ deploy-preview:
99
+ needs: quality
100
+ if: github.event_name == 'pull_request'
101
+ runs-on: ubuntu-latest
102
+ steps:
103
+ - uses: actions/checkout@v4
104
+ - uses: actions/setup-node@v4
105
+ with:
106
+ node-version: 20
107
+ cache: npm
108
+ - run: npm ci && npm run build
109
+ - name: Deploy preview
110
+ run: npx vercel deploy --prebuilt --token=${{ secrets.VERCEL_TOKEN }}
111
+ ```
112
+
113
+ ### Deployment Environment Variables
114
+
115
+ Separate environment variables by tier and manage them securely:
116
+
117
+ - **Local**: `.env.local` (gitignored, developer-managed)
118
+ - **Preview**: Vercel/Netlify project environment variables, marked "Preview" tier; use dev API keys only
119
+ - **Staging**: Staging-specific secrets in GitHub Actions or your secrets manager
120
+ - **Production**: Production secrets never visible to developers; managed by infra/ops
121
+
122
+ Audit who has access to production secrets quarterly. Rotate API keys and tokens on team member offboarding without exception.
123
+
124
+ ### Defining "Deployment Complete"
125
+
126
+ A deployment is not complete when the deploy command exits. It is complete when:
127
+
128
+ 1. The new version is serving traffic (health check passes)
129
+ 2. Error rate is not elevated above baseline
130
+ 3. Response latency p95 is not elevated above baseline
131
+ 4. At least one synthetic monitor has confirmed the critical user journey works
132
+
133
+ Automate this check in your deploy pipeline. Do not send "deploy succeeded" notifications until you have validated real traffic behavior.
134
+
135
+ ### Zero-Downtime Deployments
136
+
137
+ For apps that cannot tolerate downtime:
138
+
139
+ - **Rolling deployments**: Bring up new instances, drain old instances. Requires stateless services (no in-memory session storage).
140
+ - **Blue-green deployments**: Run two identical environments (blue = current, green = new). Switch traffic at the load balancer level. Old environment stays up as instant rollback target.
141
+ - **Feature flags**: Deploy code to production without enabling it. Enable via flag without a deployment. Fastest and most controllable rollout mechanism.
142
+
143
+ For stateful workloads (databases, file storage): always plan the data migration before the code migration. Code deploys are reversible; bad data migrations often are not.
@@ -0,0 +1,134 @@
1
+ ---
2
+ name: web-app-deployment
3
+ description: Static CDN hosting, serverless platforms, container deployments, edge runtimes, long-running servers, and blue-green deploy patterns for web apps
4
+ topics: [web-app, deployment, vercel, netlify, aws, docker, cloudflare, serverless, containers]
5
+ ---
6
+
7
+ Deployment platform selection determines your app's operational cost, performance ceiling, and scaling characteristics. Each platform has a different cost model, latency profile, and runtime constraint. Choose based on your app's rendering strategy, traffic patterns, and team's operational expertise — not on what is fashionable.
8
+
9
+ ## Summary
10
+
11
+ Web app deployment platforms range from static CDN hosting (cheapest, fastest TTFB) through serverless (pay-per-invocation, cold start concerns), containers (persistent connections, custom runtimes), edge functions (global low-latency transformations), to long-running servers (WebSockets, background jobs). Choose based on rendering strategy, traffic patterns, and operational expertise.
12
+
13
+ ## Deep Guidance
14
+
15
+ ### Static Hosting (CDN)
16
+
17
+ For SSG applications with no server-side rendering at request time:
18
+
19
+ - **Best platforms**: Cloudflare Pages, Netlify, Vercel (static tier), AWS S3 + CloudFront, GitHub Pages
20
+ - **Cost**: Near zero for low-to-medium traffic; CDN egress costs at very high traffic
21
+ - **Performance**: Best possible — globally distributed, no cold starts, ~50 ms TTFB from any major city
22
+ - **Limitations**: No request-time server logic, no secrets at request time, data freshness = deploy frequency
23
+
24
+ Configure aggressive caching headers. Static assets (hashed filenames) get `Cache-Control: immutable, max-age=31536000`. HTML pages get `Cache-Control: no-cache` (validated on every request, served from cache when fresh).
25
+
26
+ ### Serverless (Vercel, Netlify, AWS Lambda)
27
+
28
+ For SSR apps or API routes that need server logic at request time without managing servers:
29
+
30
+ - **Best platforms**: Vercel (Next.js-native), Netlify Functions, AWS Lambda + API Gateway, Cloudflare Pages Functions
31
+ - **Cost model**: Pay per invocation and compute time. Typically very cheap at low traffic, can become expensive at sustained high traffic vs. a long-running server.
32
+ - **Cold starts**: The primary performance concern. Lambda cold starts: 100–500 ms (Node.js), 1–3 seconds (container-based). Vercel/Netlify Edge Functions: 0 ms (V8 isolates, not containers).
33
+ - **Limitations**: Execution time limits (Vercel: 10–300 seconds depending on plan; Lambda: 15 minutes max), no persistent memory between invocations, no long-lived connections
34
+
35
+ Minimize cold start impact: keep bundles small (Lambda-specific: prefer ESM + tree-shaking over CommonJS), use Provisioned Concurrency for latency-critical endpoints, or migrate latency-sensitive APIs to edge functions.
36
+
37
+ ### Container (Docker, AWS ECS/Fargate, Google Cloud Run)
38
+
39
+ For apps that need more control than serverless, persistent connections, or custom runtime environments:
40
+
41
+ - **Best platforms**: AWS ECS/Fargate, Google Cloud Run, Azure Container Apps, Railway, Fly.io, self-managed Kubernetes
42
+ - **Cost model**: Per-container-hour (Fargate) or per-request with scale-to-zero (Cloud Run). More expensive than serverless at low traffic, cheaper at sustained high traffic.
43
+ - **Benefits over serverless**: No cold starts with min replicas > 0, persistent WebSocket connections, custom binaries/runtimes, larger memory limits
44
+ - **Operational overhead**: You manage container definitions, health checks, and scaling policies
45
+
46
+ Use multi-stage Docker builds to minimize image size. Target images under 200 MB:
47
+
48
+ ```dockerfile
49
+ FROM node:20-alpine AS builder
50
+ WORKDIR /app
51
+ COPY package*.json ./
52
+ RUN npm ci
53
+ COPY . .
54
+ RUN npm run build
55
+
56
+ FROM node:20-alpine AS runner
57
+ WORKDIR /app
58
+ ENV NODE_ENV=production
59
+ COPY --from=builder /app/.next ./.next
60
+ COPY --from=builder /app/public ./public
61
+ COPY --from=builder /app/package.json ./
62
+ RUN npm ci --omit=dev
63
+ USER node
64
+ EXPOSE 3000
65
+ CMD ["npm", "start"]
66
+ ```
67
+
68
+ ### Edge (Cloudflare Workers, Vercel Edge Functions)
69
+
70
+ For global, low-latency request processing with simple logic:
71
+
72
+ - **Runtime**: V8 isolates (not Node.js). Fast startup (~0 ms), runs at 300+ edge locations globally, ~1–5 ms TTFB worldwide.
73
+ - **Use cases**: Auth token validation, A/B testing, geo-routing, request rewriting, rate limiting, personalized cache headers
74
+ - **Limitations**: No Node.js built-ins (`fs`, `crypto` partially available, `child_process` unavailable), no SQLite, execution time limits (50 ms CPU time on Cloudflare free tier), no persistent file system
75
+ - **Data access**: Use edge-native databases: Cloudflare D1 (SQLite), Cloudflare KV, Upstash Redis, PlanetScale edge
76
+
77
+ Never put complex business logic in edge functions. Their value is speed and global distribution for request/response transformations, not application logic.
78
+
79
+ ### Long-Running Server (Express, Fastify, Node.js HTTP)
80
+
81
+ For apps that need WebSockets, background jobs, or full control over the request lifecycle:
82
+
83
+ - **Best platforms**: AWS EC2 + ALB, Fly.io, Railway, DigitalOcean Droplets, Hetzner (cost-efficient)
84
+ - **When to choose**: Real-time features (WebSockets, SSE), background workers, long-running database transactions, legacy apps that cannot be adapted to serverless constraints
85
+
86
+ ### Blue-Green Deployments
87
+
88
+ Blue-green deployments eliminate downtime and reduce rollback time to seconds:
89
+
90
+ 1. **Blue** = current production (100% of traffic)
91
+ 2. **Green** = new version (deployed but receiving 0% of traffic)
92
+ 3. Run smoke tests against the green environment
93
+ 4. Switch the load balancer to route 100% of traffic to green
94
+ 5. Monitor for 5–15 minutes
95
+ 6. If healthy: decommission blue. If unhealthy: switch back to blue (rollback complete in < 30 seconds)
96
+
97
+ Requirements: stateless app servers (session data in Redis/DB, not in-memory), database schema changes must be backward-compatible with both versions simultaneously.
98
+
99
+ ### Platform Selection Decision Matrix
100
+
101
+ | Criteria | Static CDN | Serverless | Container | Edge | Long-Running |
102
+ |----------|-----------|------------|-----------|------|--------------|
103
+ | SSG only | Best | Overkill | Overkill | Good | Overkill |
104
+ | SSR with SEO | — | Best | Good | Good | Good |
105
+ | Real-time (WebSocket) | No | No | Best | No | Best |
106
+ | Low traffic / cost | Best | Best | Expensive | Best | Expensive |
107
+ | High sustained traffic | Best | Expensive | Best | Best | Best |
108
+ | Cold start sensitive | N/A | Problem | Solved | Solved | Solved |
109
+ | Ops complexity | Lowest | Low | Medium | Low | High |
110
+
111
+ ### Health Checks and Readiness Probes
112
+
113
+ Every deployed service must expose health endpoints:
114
+
115
+ ```typescript
116
+ // app/api/health/route.ts
117
+ export async function GET() {
118
+ try {
119
+ // Check critical dependencies
120
+ await db.query("SELECT 1");
121
+ return Response.json({ status: "healthy", version: process.env.npm_package_version });
122
+ } catch (error) {
123
+ return Response.json({ status: "unhealthy", error: String(error) }, { status: 503 });
124
+ }
125
+ }
126
+ ```
127
+
128
+ Configure your load balancer or container orchestrator to route traffic only to healthy instances. Health check failure should trigger automatic rollback in your deployment pipeline.
129
+
130
+ ### Cost Optimization
131
+
132
+ - Use serverless for variable or low traffic; switch to containers once monthly serverless cost exceeds 2–3 baseline container instances
133
+ - CDN cache hit rate should be above 90% for SSG content — if it is not, investigate cache-busting headers
134
+ - Set spending alerts at 50% and 100% of monthly budget on cloud providers — auto-remediation (scale down) if the alert fires on unexpected traffic
@@ -0,0 +1,158 @@
1
+ ---
2
+ name: web-app-design-system
3
+ description: Responsive token systems, dark/light mode, component library patterns, and CSS methodology selection for web applications
4
+ topics: [web-app, design-system, css, tokens, dark-mode, responsive]
5
+ ---
6
+
7
+ A design system is the contract between design and engineering. Without one, components drift, spacing is inconsistent, and every engineer makes independent decisions about color, typography, and layout. A well-structured token system makes that contract explicit, machine-enforceable, and refactorable — changing a spacing scale or switching a brand color becomes a one-line edit rather than a codebase-wide search-and-replace.
8
+
9
+ ## Summary
10
+
11
+ A design system encodes design decisions as tokens at three tiers: primitive (raw values), semantic (intent-based aliases), and component-scoped overrides. Support dark/light mode via CSS custom properties with both `prefers-color-scheme` and explicit `data-theme` toggle. Commit to a consistent breakpoint scale and CSS methodology. Use headless component libraries for accessible behavior with full visual control.
12
+
13
+ ## Deep Guidance
14
+
15
+ ### Token Architecture
16
+
17
+ Design tokens are the atoms of a design system. They encode decisions — not values — at three tiers:
18
+
19
+ 1. **Primitive tokens** — Raw values with no semantic meaning: `--color-blue-500: #3b82f6`, `--spacing-4: 16px`, `--font-size-lg: 1.125rem`. Never use primitive tokens directly in components.
20
+
21
+ 2. **Semantic tokens** — Intent-based aliases of primitives: `--color-interactive: var(--color-blue-500)`, `--space-component-padding: var(--spacing-4)`. Components consume semantic tokens.
22
+
23
+ 3. **Component tokens** — Component-scoped overrides: `--button-background: var(--color-interactive)`. Allows per-component theming without touching semantic tokens.
24
+
25
+ Spacing, typography, and breakpoints belong in this hierarchy. A spacing scale (4/8/12/16/24/32/48/64px) enforced via tokens prevents the "just add a margin-top: 11px" habit that destroys visual rhythm.
26
+
27
+ ### Dark/Light Mode
28
+
29
+ Use CSS custom properties with `prefers-color-scheme` and an explicit `data-theme` attribute override:
30
+
31
+ ```css
32
+ /* Primitive layer */
33
+ :root {
34
+ --color-neutral-0: #ffffff;
35
+ --color-neutral-900: #111827;
36
+ }
37
+
38
+ /* Semantic layer — light mode defaults */
39
+ :root {
40
+ --color-surface: var(--color-neutral-0);
41
+ --color-text-primary: var(--color-neutral-900);
42
+ }
43
+
44
+ /* Dark mode via media query */
45
+ @media (prefers-color-scheme: dark) {
46
+ :root {
47
+ --color-surface: var(--color-neutral-900);
48
+ --color-text-primary: var(--color-neutral-0);
49
+ }
50
+ }
51
+
52
+ /* Manual override via JS toggle */
53
+ [data-theme="dark"] {
54
+ --color-surface: var(--color-neutral-900);
55
+ --color-text-primary: var(--color-neutral-0);
56
+ }
57
+ ```
58
+
59
+ Always support both mechanisms: `prefers-color-scheme` for first-visit experience, `data-theme` for user preference stored in `localStorage`.
60
+
61
+ ### CSS Methodology Selection
62
+
63
+ | Approach | Best For | Trade-offs |
64
+ |---|---|---|
65
+ | Utility-first (Tailwind) | Rapid iteration, small teams, consistent constraints | Verbose JSX, limited custom design expression |
66
+ | CSS Modules | Scoped styles with full CSS power, no runtime cost | Manual naming, no global token enforcement |
67
+ | CSS-in-JS (Emotion, styled-components) | Dynamic theming, colocation, TypeScript safety | Runtime cost, hydration complexity in SSR |
68
+ | Zero-runtime (Vanilla Extract, Linaria) | SSR-safe, type-safe tokens, no runtime overhead | Build-time complexity, less dynamic |
69
+
70
+ For most production web apps, the recommendation is: **Tailwind + CSS custom properties** for utility-heavy UIs, or **CSS Modules + tokens** for design-system-first projects where designers own the token layer.
71
+
72
+ ### Responsive Breakpoints
73
+
74
+ Commit to a consistent breakpoint scale and never deviate:
75
+
76
+ ```css
77
+ /* Mobile-first breakpoints */
78
+ --bp-sm: 640px; /* Large phones */
79
+ --bp-md: 768px; /* Tablets */
80
+ --bp-lg: 1024px; /* Small desktops */
81
+ --bp-xl: 1280px; /* Large desktops */
82
+ --bp-2xl: 1536px; /* Wide screens */
83
+ ```
84
+
85
+ Use `min-width` queries exclusively (mobile-first). Avoid magic numbers in media queries — always reference the token scale.
86
+
87
+ ### Component Library Patterns
88
+
89
+ A component library is the implementation layer of the design system. Key architectural decisions:
90
+
91
+ **Compound components over prop explosion:**
92
+
93
+ ```tsx
94
+ // BAD: Props explode as requirements grow
95
+ <Select
96
+ label="Country"
97
+ options={countries}
98
+ placeholder="Select..."
99
+ isSearchable
100
+ isClearable
101
+ isMulti
102
+ maxSelectedItems={3}
103
+ />
104
+
105
+ // GOOD: Compound pattern — composable, extensible
106
+ <Select value={value} onChange={setValue}>
107
+ <Select.Trigger>
108
+ <Select.Value placeholder="Select country..." />
109
+ </Select.Trigger>
110
+ <Select.Content>
111
+ <Select.Search />
112
+ {countries.map(c => (
113
+ <Select.Item key={c.code} value={c.code}>{c.name}</Select.Item>
114
+ ))}
115
+ </Select.Content>
116
+ </Select>
117
+ ```
118
+
119
+ **Headless components for styling flexibility:**
120
+ Use Radix UI, Headless UI, or React Aria as the unstyled behavior layer. Wire your token system on top. This gives accessible keyboard navigation and ARIA semantics for free while preserving full visual control.
121
+
122
+ **Token enforcement via linting:**
123
+ Use `stylelint-no-invalid-hex` and custom Stylelint rules (or ESLint for CSS-in-JS) to reject hardcoded color values not referencing a token. Automate this in CI.
124
+
125
+ ### Typography Scale
126
+
127
+ Build a modular type scale with explicit roles:
128
+
129
+ ```css
130
+ :root {
131
+ /* Scale steps — use a modular scale ratio (1.25 or 1.333) */
132
+ --text-xs: 0.75rem; /* 12px — labels, captions */
133
+ --text-sm: 0.875rem; /* 14px — body secondary */
134
+ --text-base: 1rem; /* 16px — body primary */
135
+ --text-lg: 1.125rem; /* 18px — subheadings */
136
+ --text-xl: 1.25rem; /* 20px — section headings */
137
+ --text-2xl: 1.5rem; /* 24px — page headings */
138
+ --text-3xl: 1.875rem; /* 30px — hero headings */
139
+
140
+ /* Line heights tied to text size for proper vertical rhythm */
141
+ --leading-tight: 1.25;
142
+ --leading-normal: 1.5;
143
+ --leading-relaxed: 1.75;
144
+ }
145
+ ```
146
+
147
+ Never use pixel values for font sizes in component code — only reference scale tokens. This ensures user font size preferences (browser zoom, accessibility settings) are respected.
148
+
149
+ ### Design Token Pipeline
150
+
151
+ For teams with a Figma design system, automate the token pipeline:
152
+
153
+ 1. Designers export tokens from Figma using the Tokens Studio plugin as a JSON file
154
+ 2. CI runs a token transformer (Style Dictionary) that converts JSON to CSS custom properties, TypeScript constants, and platform-specific formats
155
+ 3. The generated files are committed to the repository and reviewed in PRs
156
+ 4. Token changes are flagged in design review before code review
157
+
158
+ This makes "design changed the brand blue" a designer-owned PR rather than an engineering ticket.