wiggum-cli 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/README.md +341 -0
- package/bin/ralph.js +8 -0
- package/dist/ai/enhancer.d.ts +100 -0
- package/dist/ai/enhancer.d.ts.map +1 -0
- package/dist/ai/enhancer.js +233 -0
- package/dist/ai/enhancer.js.map +1 -0
- package/dist/ai/index.d.ts +8 -0
- package/dist/ai/index.d.ts.map +1 -0
- package/dist/ai/index.js +11 -0
- package/dist/ai/index.js.map +1 -0
- package/dist/ai/prompts.d.ts +26 -0
- package/dist/ai/prompts.d.ts.map +1 -0
- package/dist/ai/prompts.js +201 -0
- package/dist/ai/prompts.js.map +1 -0
- package/dist/ai/providers.d.ts +35 -0
- package/dist/ai/providers.d.ts.map +1 -0
- package/dist/ai/providers.js +104 -0
- package/dist/ai/providers.js.map +1 -0
- package/dist/cli.d.ts +6 -0
- package/dist/cli.d.ts.map +1 -0
- package/dist/cli.js +196 -0
- package/dist/cli.js.map +1 -0
- package/dist/commands/init.d.ts +16 -0
- package/dist/commands/init.d.ts.map +1 -0
- package/dist/commands/init.js +124 -0
- package/dist/commands/init.js.map +1 -0
- package/dist/commands/monitor.d.ts +17 -0
- package/dist/commands/monitor.d.ts.map +1 -0
- package/dist/commands/monitor.js +342 -0
- package/dist/commands/monitor.js.map +1 -0
- package/dist/commands/new.d.ts +19 -0
- package/dist/commands/new.d.ts.map +1 -0
- package/dist/commands/new.js +272 -0
- package/dist/commands/new.js.map +1 -0
- package/dist/commands/run.d.ts +16 -0
- package/dist/commands/run.d.ts.map +1 -0
- package/dist/commands/run.js +175 -0
- package/dist/commands/run.js.map +1 -0
- package/dist/generator/config.d.ts +59 -0
- package/dist/generator/config.d.ts.map +1 -0
- package/dist/generator/config.js +68 -0
- package/dist/generator/config.js.map +1 -0
- package/dist/generator/index.d.ts +64 -0
- package/dist/generator/index.d.ts.map +1 -0
- package/dist/generator/index.js +147 -0
- package/dist/generator/index.js.map +1 -0
- package/dist/generator/templates.d.ts +70 -0
- package/dist/generator/templates.d.ts.map +1 -0
- package/dist/generator/templates.js +296 -0
- package/dist/generator/templates.js.map +1 -0
- package/dist/generator/writer.d.ts +93 -0
- package/dist/generator/writer.d.ts.map +1 -0
- package/dist/generator/writer.js +213 -0
- package/dist/generator/writer.js.map +1 -0
- package/dist/index.d.ts +12 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +17 -0
- package/dist/index.js.map +1 -0
- package/dist/scanner/detectors/core/framework.d.ts +11 -0
- package/dist/scanner/detectors/core/framework.d.ts.map +1 -0
- package/dist/scanner/detectors/core/framework.js +275 -0
- package/dist/scanner/detectors/core/framework.js.map +1 -0
- package/dist/scanner/detectors/core/packageManager.d.ts +11 -0
- package/dist/scanner/detectors/core/packageManager.d.ts.map +1 -0
- package/dist/scanner/detectors/core/packageManager.js +74 -0
- package/dist/scanner/detectors/core/packageManager.js.map +1 -0
- package/dist/scanner/detectors/core/styling.d.ts +12 -0
- package/dist/scanner/detectors/core/styling.d.ts.map +1 -0
- package/dist/scanner/detectors/core/styling.js +230 -0
- package/dist/scanner/detectors/core/styling.js.map +1 -0
- package/dist/scanner/detectors/core/testing.d.ts +12 -0
- package/dist/scanner/detectors/core/testing.d.ts.map +1 -0
- package/dist/scanner/detectors/core/testing.js +190 -0
- package/dist/scanner/detectors/core/testing.js.map +1 -0
- package/dist/scanner/detectors/data/api.d.ts +12 -0
- package/dist/scanner/detectors/data/api.d.ts.map +1 -0
- package/dist/scanner/detectors/data/api.js +261 -0
- package/dist/scanner/detectors/data/api.js.map +1 -0
- package/dist/scanner/detectors/data/database.d.ts +12 -0
- package/dist/scanner/detectors/data/database.d.ts.map +1 -0
- package/dist/scanner/detectors/data/database.js +213 -0
- package/dist/scanner/detectors/data/database.js.map +1 -0
- package/dist/scanner/detectors/data/orm.d.ts +12 -0
- package/dist/scanner/detectors/data/orm.d.ts.map +1 -0
- package/dist/scanner/detectors/data/orm.js +160 -0
- package/dist/scanner/detectors/data/orm.js.map +1 -0
- package/dist/scanner/detectors/frontend/formHandling.d.ts +12 -0
- package/dist/scanner/detectors/frontend/formHandling.d.ts.map +1 -0
- package/dist/scanner/detectors/frontend/formHandling.js +211 -0
- package/dist/scanner/detectors/frontend/formHandling.js.map +1 -0
- package/dist/scanner/detectors/frontend/stateManagement.d.ts +12 -0
- package/dist/scanner/detectors/frontend/stateManagement.d.ts.map +1 -0
- package/dist/scanner/detectors/frontend/stateManagement.js +221 -0
- package/dist/scanner/detectors/frontend/stateManagement.js.map +1 -0
- package/dist/scanner/detectors/frontend/uiComponents.d.ts +12 -0
- package/dist/scanner/detectors/frontend/uiComponents.d.ts.map +1 -0
- package/dist/scanner/detectors/frontend/uiComponents.js +285 -0
- package/dist/scanner/detectors/frontend/uiComponents.js.map +1 -0
- package/dist/scanner/detectors/infra/deployment.d.ts +12 -0
- package/dist/scanner/detectors/infra/deployment.d.ts.map +1 -0
- package/dist/scanner/detectors/infra/deployment.js +301 -0
- package/dist/scanner/detectors/infra/deployment.js.map +1 -0
- package/dist/scanner/detectors/infra/monorepo.d.ts +12 -0
- package/dist/scanner/detectors/infra/monorepo.d.ts.map +1 -0
- package/dist/scanner/detectors/infra/monorepo.js +219 -0
- package/dist/scanner/detectors/infra/monorepo.js.map +1 -0
- package/dist/scanner/detectors/mcp/mcpProject.d.ts +12 -0
- package/dist/scanner/detectors/mcp/mcpProject.d.ts.map +1 -0
- package/dist/scanner/detectors/mcp/mcpProject.js +154 -0
- package/dist/scanner/detectors/mcp/mcpProject.js.map +1 -0
- package/dist/scanner/detectors/mcp/mcpServers.d.ts +17 -0
- package/dist/scanner/detectors/mcp/mcpServers.d.ts.map +1 -0
- package/dist/scanner/detectors/mcp/mcpServers.js +193 -0
- package/dist/scanner/detectors/mcp/mcpServers.js.map +1 -0
- package/dist/scanner/detectors/services/analytics.d.ts +12 -0
- package/dist/scanner/detectors/services/analytics.d.ts.map +1 -0
- package/dist/scanner/detectors/services/analytics.js +236 -0
- package/dist/scanner/detectors/services/analytics.js.map +1 -0
- package/dist/scanner/detectors/services/auth.d.ts +12 -0
- package/dist/scanner/detectors/services/auth.d.ts.map +1 -0
- package/dist/scanner/detectors/services/auth.js +217 -0
- package/dist/scanner/detectors/services/auth.js.map +1 -0
- package/dist/scanner/detectors/services/email.d.ts +12 -0
- package/dist/scanner/detectors/services/email.d.ts.map +1 -0
- package/dist/scanner/detectors/services/email.js +211 -0
- package/dist/scanner/detectors/services/email.js.map +1 -0
- package/dist/scanner/detectors/services/payments.d.ts +12 -0
- package/dist/scanner/detectors/services/payments.d.ts.map +1 -0
- package/dist/scanner/detectors/services/payments.js +185 -0
- package/dist/scanner/detectors/services/payments.js.map +1 -0
- package/dist/scanner/detectors/utils.d.ts +160 -0
- package/dist/scanner/detectors/utils.d.ts.map +1 -0
- package/dist/scanner/detectors/utils.js +222 -0
- package/dist/scanner/detectors/utils.js.map +1 -0
- package/dist/scanner/index.d.ts +42 -0
- package/dist/scanner/index.d.ts.map +1 -0
- package/dist/scanner/index.js +282 -0
- package/dist/scanner/index.js.map +1 -0
- package/dist/scanner/registry.d.ts +43 -0
- package/dist/scanner/registry.d.ts.map +1 -0
- package/dist/scanner/registry.js +243 -0
- package/dist/scanner/registry.js.map +1 -0
- package/dist/scanner/types.d.ts +112 -0
- package/dist/scanner/types.d.ts.map +1 -0
- package/dist/scanner/types.js +6 -0
- package/dist/scanner/types.js.map +1 -0
- package/dist/templates/config/ralph.config.js.tmpl +38 -0
- package/dist/templates/guides/AGENTS.md.tmpl +100 -0
- package/dist/templates/guides/FRONTEND.md.tmpl +523 -0
- package/dist/templates/guides/PERFORMANCE.md.tmpl +264 -0
- package/dist/templates/guides/SECURITY.md.tmpl +100 -0
- package/dist/templates/prompts/PROMPT.md.tmpl +77 -0
- package/dist/templates/prompts/PROMPT_e2e.md.tmpl +234 -0
- package/dist/templates/prompts/PROMPT_feature.md.tmpl +83 -0
- package/dist/templates/prompts/PROMPT_review.md.tmpl +167 -0
- package/dist/templates/prompts/PROMPT_verify.md.tmpl +72 -0
- package/dist/templates/root/.gitignore.tmpl +5 -0
- package/dist/templates/root/LEARNINGS.md.tmpl +24 -0
- package/dist/templates/root/README.md.tmpl +61 -0
- package/dist/templates/scripts/feature-loop.sh.tmpl +267 -0
- package/dist/templates/scripts/loop.sh.tmpl +59 -0
- package/dist/templates/scripts/ralph-monitor.sh.tmpl +244 -0
- package/dist/templates/specs/README.md.tmpl +57 -0
- package/dist/templates/specs/_example.md.tmpl +71 -0
- package/dist/utils/config.d.ts +95 -0
- package/dist/utils/config.d.ts.map +1 -0
- package/dist/utils/config.js +148 -0
- package/dist/utils/config.js.map +1 -0
- package/dist/utils/header.d.ts +5 -0
- package/dist/utils/header.d.ts.map +1 -0
- package/dist/utils/header.js +15 -0
- package/dist/utils/header.js.map +1 -0
- package/dist/utils/logger.d.ts +11 -0
- package/dist/utils/logger.d.ts.map +1 -0
- package/dist/utils/logger.js +24 -0
- package/dist/utils/logger.js.map +1 -0
- package/package.json +44 -0
- package/src/ai/enhancer.ts +350 -0
- package/src/ai/index.ts +38 -0
- package/src/ai/prompts.ts +217 -0
- package/src/ai/providers.ts +136 -0
- package/src/cli.ts +255 -0
- package/src/commands/init.ts +149 -0
- package/src/commands/monitor.ts +412 -0
- package/src/commands/new.ts +312 -0
- package/src/commands/run.ts +214 -0
- package/src/generator/config.ts +116 -0
- package/src/generator/index.ts +227 -0
- package/src/generator/templates.ts +412 -0
- package/src/generator/writer.ts +293 -0
- package/src/index.ts +41 -0
- package/src/scanner/detectors/core/framework.ts +332 -0
- package/src/scanner/detectors/core/packageManager.ts +91 -0
- package/src/scanner/detectors/core/styling.ts +261 -0
- package/src/scanner/detectors/core/testing.ts +221 -0
- package/src/scanner/detectors/data/api.ts +303 -0
- package/src/scanner/detectors/data/database.ts +245 -0
- package/src/scanner/detectors/data/orm.ts +180 -0
- package/src/scanner/detectors/frontend/formHandling.ts +244 -0
- package/src/scanner/detectors/frontend/stateManagement.ts +261 -0
- package/src/scanner/detectors/frontend/uiComponents.ts +328 -0
- package/src/scanner/detectors/infra/deployment.ts +343 -0
- package/src/scanner/detectors/infra/monorepo.ts +251 -0
- package/src/scanner/detectors/mcp/mcpProject.ts +176 -0
- package/src/scanner/detectors/mcp/mcpServers.ts +237 -0
- package/src/scanner/detectors/services/analytics.ts +273 -0
- package/src/scanner/detectors/services/auth.ts +254 -0
- package/src/scanner/detectors/services/email.ts +244 -0
- package/src/scanner/detectors/services/payments.ts +213 -0
- package/src/scanner/detectors/utils.ts +251 -0
- package/src/scanner/index.ts +354 -0
- package/src/scanner/registry.ts +301 -0
- package/src/scanner/types.ts +152 -0
- package/src/templates/config/ralph.config.js.tmpl +38 -0
- package/src/templates/guides/AGENTS.md.tmpl +100 -0
- package/src/templates/guides/FRONTEND.md.tmpl +523 -0
- package/src/templates/guides/PERFORMANCE.md.tmpl +264 -0
- package/src/templates/guides/SECURITY.md.tmpl +100 -0
- package/src/templates/prompts/PROMPT.md.tmpl +77 -0
- package/src/templates/prompts/PROMPT_e2e.md.tmpl +234 -0
- package/src/templates/prompts/PROMPT_feature.md.tmpl +83 -0
- package/src/templates/prompts/PROMPT_review.md.tmpl +167 -0
- package/src/templates/prompts/PROMPT_verify.md.tmpl +72 -0
- package/src/templates/root/.gitignore.tmpl +5 -0
- package/src/templates/root/LEARNINGS.md.tmpl +24 -0
- package/src/templates/root/README.md.tmpl +61 -0
- package/src/templates/scripts/feature-loop.sh.tmpl +267 -0
- package/src/templates/scripts/loop.sh.tmpl +59 -0
- package/src/templates/scripts/ralph-monitor.sh.tmpl +244 -0
- package/src/templates/specs/README.md.tmpl +57 -0
- package/src/templates/specs/_example.md.tmpl +71 -0
- package/src/utils/config.ts +221 -0
- package/src/utils/header.ts +15 -0
- package/src/utils/logger.ts +28 -0
- package/tsconfig.json +19 -0
|
@@ -0,0 +1,264 @@
|
|
|
1
|
+
# Performance Patterns
|
|
2
|
+
|
|
3
|
+
{{framework}} performance best practices for implementation phases.
|
|
4
|
+
Reference when writing new components, data fetching, or optimizing existing code.
|
|
5
|
+
|
|
6
|
+
## Critical: Eliminate Waterfalls
|
|
7
|
+
|
|
8
|
+
The #1 performance killer. Sequential awaits add full network latency per request.
|
|
9
|
+
|
|
10
|
+
### Bad: Sequential Fetches
|
|
11
|
+
```typescript
|
|
12
|
+
// 3 round trips = 3x latency
|
|
13
|
+
const user = await getUser(id);
|
|
14
|
+
const posts = await getPosts(user.id);
|
|
15
|
+
const comments = await getComments(posts[0].id);
|
|
16
|
+
```
|
|
17
|
+
|
|
18
|
+
### Good: Parallel Fetches
|
|
19
|
+
```typescript
|
|
20
|
+
// 1 round trip for independent data
|
|
21
|
+
const [user, posts, settings] = await Promise.all([
|
|
22
|
+
getUser(id),
|
|
23
|
+
getPosts(id),
|
|
24
|
+
getSettings(id),
|
|
25
|
+
]);
|
|
26
|
+
```
|
|
27
|
+
|
|
28
|
+
### Good: Defer Awaits
|
|
29
|
+
```typescript
|
|
30
|
+
// Start fetch immediately, await when needed
|
|
31
|
+
const dataPromise = fetchData(); // no await
|
|
32
|
+
// ... do other work ...
|
|
33
|
+
const data = await dataPromise; // await at usage
|
|
34
|
+
```
|
|
35
|
+
|
|
36
|
+
### Good: Suspense Boundaries
|
|
37
|
+
```tsx
|
|
38
|
+
// Show UI before data loads
|
|
39
|
+
<Suspense fallback={<Skeleton />}>
|
|
40
|
+
<DataComponent /> {/* fetches inside */}
|
|
41
|
+
</Suspense>
|
|
42
|
+
```
|
|
43
|
+
|
|
44
|
+
## Critical: Bundle Size
|
|
45
|
+
|
|
46
|
+
Reduces Time to Interactive and Largest Contentful Paint.
|
|
47
|
+
|
|
48
|
+
### Bad: Barrel Imports
|
|
49
|
+
```typescript
|
|
50
|
+
// Imports entire library, 200-800ms cold start penalty
|
|
51
|
+
import { Button } from '@/components/ui';
|
|
52
|
+
```
|
|
53
|
+
|
|
54
|
+
### Good: Direct Imports
|
|
55
|
+
```typescript
|
|
56
|
+
// Import only what's needed
|
|
57
|
+
import { Button } from '@/components/ui/button';
|
|
58
|
+
```
|
|
59
|
+
|
|
60
|
+
### Good: Lazy Load Heavy Components
|
|
61
|
+
```typescript
|
|
62
|
+
// Defer Monaco Editor (~300KB) until needed
|
|
63
|
+
const Editor = dynamic(() => import('@/components/editor'), {
|
|
64
|
+
loading: () => <Skeleton />,
|
|
65
|
+
ssr: false,
|
|
66
|
+
});
|
|
67
|
+
```
|
|
68
|
+
|
|
69
|
+
### Good: Defer Third-Party Scripts
|
|
70
|
+
```typescript
|
|
71
|
+
// Load analytics after hydration
|
|
72
|
+
useEffect(() => {
|
|
73
|
+
import('posthog-js').then((posthog) => posthog.init(...));
|
|
74
|
+
}, []);
|
|
75
|
+
```
|
|
76
|
+
|
|
77
|
+
## High: Server-Side Performance
|
|
78
|
+
|
|
79
|
+
### Use React.cache() for Request Deduplication
|
|
80
|
+
```typescript
|
|
81
|
+
// Same data fetched by multiple components = 1 request
|
|
82
|
+
import { cache } from 'react';
|
|
83
|
+
|
|
84
|
+
export const getUser = cache(async (id: string) => {
|
|
85
|
+
return db.user.findUnique({ where: { id } });
|
|
86
|
+
});
|
|
87
|
+
```
|
|
88
|
+
|
|
89
|
+
### Minimize RSC Serialization
|
|
90
|
+
```typescript
|
|
91
|
+
// Bad: Pass entire object
|
|
92
|
+
<ClientComponent user={user} /> // serializes all fields
|
|
93
|
+
|
|
94
|
+
// Good: Pass only needed fields
|
|
95
|
+
<ClientComponent name={user.name} avatar={user.avatar} />
|
|
96
|
+
```
|
|
97
|
+
|
|
98
|
+
### Use after() for Non-Blocking Work
|
|
99
|
+
```typescript
|
|
100
|
+
import { after } from 'next/server';
|
|
101
|
+
|
|
102
|
+
export async function POST(request: Request) {
|
|
103
|
+
const data = await request.json();
|
|
104
|
+
|
|
105
|
+
// Respond immediately
|
|
106
|
+
after(async () => {
|
|
107
|
+
// Analytics, logging - doesn't block response
|
|
108
|
+
await trackEvent('form_submit', data);
|
|
109
|
+
});
|
|
110
|
+
|
|
111
|
+
return Response.json({ success: true });
|
|
112
|
+
}
|
|
113
|
+
```
|
|
114
|
+
|
|
115
|
+
## Medium: Re-render Optimization
|
|
116
|
+
|
|
117
|
+
### Defer useSearchParams
|
|
118
|
+
```typescript
|
|
119
|
+
// Bad: Subscribes entire component to URL changes
|
|
120
|
+
function Page() {
|
|
121
|
+
const searchParams = useSearchParams(); // triggers re-render on any URL change
|
|
122
|
+
return <Child params={searchParams} />;
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
// Good: Read in child that needs it
|
|
126
|
+
function Page() {
|
|
127
|
+
return <Child />; // no subscription here
|
|
128
|
+
}
|
|
129
|
+
function Child() {
|
|
130
|
+
const searchParams = useSearchParams(); // only this re-renders
|
|
131
|
+
}
|
|
132
|
+
```
|
|
133
|
+
|
|
134
|
+
### Use Functional setState
|
|
135
|
+
```typescript
|
|
136
|
+
// Bad: Stale closure risk, recreates callback
|
|
137
|
+
const increment = useCallback(() => {
|
|
138
|
+
setCount(count + 1);
|
|
139
|
+
}, [count]);
|
|
140
|
+
|
|
141
|
+
// Good: Always fresh, stable callback
|
|
142
|
+
const increment = useCallback(() => {
|
|
143
|
+
setCount((c) => c + 1);
|
|
144
|
+
}, []);
|
|
145
|
+
```
|
|
146
|
+
|
|
147
|
+
### Lazy Initialize Expensive State
|
|
148
|
+
```typescript
|
|
149
|
+
// Bad: Runs on every render
|
|
150
|
+
const [data, setData] = useState(expensiveComputation());
|
|
151
|
+
|
|
152
|
+
// Good: Runs only on mount
|
|
153
|
+
const [data, setData] = useState(() => expensiveComputation());
|
|
154
|
+
```
|
|
155
|
+
|
|
156
|
+
### Use Transitions for Non-Urgent Updates
|
|
157
|
+
```typescript
|
|
158
|
+
const [isPending, startTransition] = useTransition();
|
|
159
|
+
|
|
160
|
+
function handleSearch(query: string) {
|
|
161
|
+
// Urgent: update input immediately
|
|
162
|
+
setQuery(query);
|
|
163
|
+
|
|
164
|
+
// Non-urgent: can be interrupted
|
|
165
|
+
startTransition(() => {
|
|
166
|
+
setFilteredResults(filterResults(query));
|
|
167
|
+
});
|
|
168
|
+
}
|
|
169
|
+
```
|
|
170
|
+
|
|
171
|
+
## Medium: Rendering Performance
|
|
172
|
+
|
|
173
|
+
### Hoist Static JSX
|
|
174
|
+
```typescript
|
|
175
|
+
// Bad: Recreated every render
|
|
176
|
+
function Component() {
|
|
177
|
+
const icon = <Icon size={24} />; // new object each time
|
|
178
|
+
return <Button icon={icon} />;
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
// Good: Created once
|
|
182
|
+
const icon = <Icon size={24} />;
|
|
183
|
+
function Component() {
|
|
184
|
+
return <Button icon={icon} />;
|
|
185
|
+
}
|
|
186
|
+
```
|
|
187
|
+
|
|
188
|
+
### Use content-visibility for Long Lists
|
|
189
|
+
```css
|
|
190
|
+
.list-item {
|
|
191
|
+
content-visibility: auto;
|
|
192
|
+
contain-intrinsic-size: 0 80px; /* estimated height */
|
|
193
|
+
}
|
|
194
|
+
```
|
|
195
|
+
Skips layout/paint for off-screen items. 1000-item list renders 10x faster.
|
|
196
|
+
|
|
197
|
+
### Prevent Hydration Mismatches
|
|
198
|
+
```tsx
|
|
199
|
+
// For theme/locale that differs server vs client
|
|
200
|
+
// Use inline script to set data attribute before React hydrates
|
|
201
|
+
<script>
|
|
202
|
+
{`document.documentElement.dataset.theme = localStorage.getItem('theme') || 'light'`}
|
|
203
|
+
</script>
|
|
204
|
+
```
|
|
205
|
+
|
|
206
|
+
## Low-Medium: JavaScript Optimizations
|
|
207
|
+
|
|
208
|
+
### Build Index Maps for Repeated Lookups
|
|
209
|
+
```typescript
|
|
210
|
+
// Bad: O(n) per lookup
|
|
211
|
+
users.find((u) => u.id === id);
|
|
212
|
+
|
|
213
|
+
// Good: O(1) per lookup
|
|
214
|
+
const userMap = new Map(users.map((u) => [u.id, u]));
|
|
215
|
+
userMap.get(id);
|
|
216
|
+
```
|
|
217
|
+
|
|
218
|
+
### Use Set for Membership Checks
|
|
219
|
+
```typescript
|
|
220
|
+
// Bad: O(n) per check
|
|
221
|
+
const isSelected = selectedIds.includes(id);
|
|
222
|
+
|
|
223
|
+
// Good: O(1) per check
|
|
224
|
+
const selectedSet = new Set(selectedIds);
|
|
225
|
+
const isSelected = selectedSet.has(id);
|
|
226
|
+
```
|
|
227
|
+
|
|
228
|
+
### Single-Pass for Min/Max
|
|
229
|
+
```typescript
|
|
230
|
+
// Bad: O(n log n)
|
|
231
|
+
const latest = items.sort((a, b) => b.date - a.date)[0];
|
|
232
|
+
|
|
233
|
+
// Good: O(n)
|
|
234
|
+
const latest = items.reduce((max, item) =>
|
|
235
|
+
item.date > max.date ? item : max
|
|
236
|
+
);
|
|
237
|
+
```
|
|
238
|
+
|
|
239
|
+
### Use .toSorted() to Avoid Mutation
|
|
240
|
+
```typescript
|
|
241
|
+
// Bad: Mutates original array (breaks React)
|
|
242
|
+
items.sort((a, b) => a.name.localeCompare(b.name));
|
|
243
|
+
|
|
244
|
+
// Good: Returns new sorted array
|
|
245
|
+
items.toSorted((a, b) => a.name.localeCompare(b.name));
|
|
246
|
+
```
|
|
247
|
+
|
|
248
|
+
## Quick Reference
|
|
249
|
+
|
|
250
|
+
| Issue | Solution |
|
|
251
|
+
|-------|----------|
|
|
252
|
+
| Sequential fetches | `Promise.all()` or defer awaits |
|
|
253
|
+
| Large bundle | Direct imports, `next/dynamic` |
|
|
254
|
+
| Duplicate requests | `React.cache()`, SWR |
|
|
255
|
+
| Unnecessary re-renders | Functional setState, transitions |
|
|
256
|
+
| Slow lists | `content-visibility: auto` |
|
|
257
|
+
| Repeated lookups | Map/Set indexes |
|
|
258
|
+
|
|
259
|
+
## When to Apply
|
|
260
|
+
|
|
261
|
+
- **New components**: Check waterfall and bundle patterns
|
|
262
|
+
- **Data fetching**: Use parallel fetches, React.cache()
|
|
263
|
+
- **Performance issues**: Profile first, then apply relevant patterns
|
|
264
|
+
- **Code review**: Flag sequential awaits and barrel imports
|
|
@@ -0,0 +1,100 @@
|
|
|
1
|
+
# Security Review Checklist
|
|
2
|
+
|
|
3
|
+
Red-team security review for each task. Check before committing.
|
|
4
|
+
|
|
5
|
+
## Quick Scan (Every Task)
|
|
6
|
+
|
|
7
|
+
Run through these checks for any code you've written or modified:
|
|
8
|
+
|
|
9
|
+
### Input Validation
|
|
10
|
+
- [ ] User inputs are validated and sanitized
|
|
11
|
+
- [ ] File uploads check type, size, and content
|
|
12
|
+
- [ ] URL parameters are validated before use
|
|
13
|
+
- [ ] JSON/form data is schema-validated
|
|
14
|
+
|
|
15
|
+
### Injection Prevention
|
|
16
|
+
- [ ] SQL: Using parameterized queries (Supabase client handles this)
|
|
17
|
+
- [ ] XSS: User content is escaped before rendering
|
|
18
|
+
- [ ] Command injection: No shell commands with user input
|
|
19
|
+
- [ ] Path traversal: File paths are validated, no `../` allowed
|
|
20
|
+
|
|
21
|
+
### Authentication & Authorization
|
|
22
|
+
- [ ] Protected routes check authentication
|
|
23
|
+
- [ ] API endpoints verify user permissions
|
|
24
|
+
- [ ] Sensitive actions require re-authentication
|
|
25
|
+
- [ ] No secrets in client-side code
|
|
26
|
+
|
|
27
|
+
### Data Exposure
|
|
28
|
+
- [ ] API responses don't leak sensitive fields
|
|
29
|
+
- [ ] Error messages don't expose internals
|
|
30
|
+
- [ ] Logs don't contain PII or secrets
|
|
31
|
+
- [ ] Database queries filter by user ownership
|
|
32
|
+
|
|
33
|
+
## Deep Scan (Sensitive Features)
|
|
34
|
+
|
|
35
|
+
For auth, payments, data export, admin features:
|
|
36
|
+
|
|
37
|
+
### OWASP Top 10 Check
|
|
38
|
+
| Risk | Check |
|
|
39
|
+
|------|-------|
|
|
40
|
+
| Injection | Parameterized queries, no dynamic code execution |
|
|
41
|
+
| Broken Auth | Session handling, token expiry |
|
|
42
|
+
| Sensitive Data | Encryption at rest/transit |
|
|
43
|
+
| XXE | Disable external entities in XML parsers |
|
|
44
|
+
| Broken Access | Row-level security, ownership checks |
|
|
45
|
+
| Misconfig | No debug mode, secure headers |
|
|
46
|
+
| XSS | Content-Security-Policy, output encoding |
|
|
47
|
+
| Insecure Deserialization | Validate before deserialize |
|
|
48
|
+
| Vulnerable Components | Check {{packageManager}} audit |
|
|
49
|
+
| Logging | Audit trail, no sensitive data logged |
|
|
50
|
+
|
|
51
|
+
### Supabase-Specific
|
|
52
|
+
- [ ] RLS policies enabled on tables with user data
|
|
53
|
+
- [ ] RLS policies test both SELECT and INSERT/UPDATE/DELETE
|
|
54
|
+
- [ ] Service role key only used server-side
|
|
55
|
+
- [ ] Anon key permissions are minimal
|
|
56
|
+
|
|
57
|
+
### {{framework}}-Specific
|
|
58
|
+
- [ ] Server actions validate input
|
|
59
|
+
- [ ] API routes check authentication
|
|
60
|
+
- [ ] No sensitive data in client components
|
|
61
|
+
- [ ] Environment variables not exposed to client (no NEXT_PUBLIC_ for secrets)
|
|
62
|
+
|
|
63
|
+
## Red Team Prompts
|
|
64
|
+
|
|
65
|
+
Ask yourself:
|
|
66
|
+
1. **Can I bypass auth?** Try accessing protected routes/APIs without login
|
|
67
|
+
2. **Can I access other users' data?** Change IDs in requests
|
|
68
|
+
3. **Can I inject malicious content?** Try `<script>`, SQL fragments, `../`
|
|
69
|
+
4. **Can I cause a DoS?** Large payloads, infinite loops, resource exhaustion
|
|
70
|
+
5. **Can I exfiltrate data?** Check what the API returns, console logs
|
|
71
|
+
|
|
72
|
+
## Commands
|
|
73
|
+
|
|
74
|
+
```bash
|
|
75
|
+
# Check for vulnerable dependencies
|
|
76
|
+
cd {{appDir}} && {{packageManager}} audit
|
|
77
|
+
|
|
78
|
+
# Check for secrets in code (should return nothing)
|
|
79
|
+
cd {{appDir}} && grep -r "sk_live\|password=\|secret=" --include="*.ts" --include="*.tsx" .
|
|
80
|
+
|
|
81
|
+
# Check RLS policies
|
|
82
|
+
# Use Supabase MCP: mcp__supabase__get_advisors with type: "security"
|
|
83
|
+
```
|
|
84
|
+
|
|
85
|
+
## When to Flag
|
|
86
|
+
|
|
87
|
+
Stop and investigate if you find:
|
|
88
|
+
- Direct SQL string concatenation
|
|
89
|
+
- Dynamic code execution with user data
|
|
90
|
+
- Hardcoded credentials or API keys
|
|
91
|
+
- Missing authentication on sensitive endpoints
|
|
92
|
+
- User IDs accepted from client without verification
|
|
93
|
+
- File operations with user-controlled paths
|
|
94
|
+
|
|
95
|
+
## Fixing Issues
|
|
96
|
+
|
|
97
|
+
1. **Document** the vulnerability in the implementation plan
|
|
98
|
+
2. **Fix** before committing (don't leave for later)
|
|
99
|
+
3. **Test** the fix (try to exploit it)
|
|
100
|
+
4. **Learn** - add to LEARNINGS.md if it's a new pattern
|
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
## Context
|
|
2
|
+
Study @.ralph/AGENTS.md for commands and patterns.
|
|
3
|
+
Study @.ralph/specs/$FEATURE.md for feature specification.
|
|
4
|
+
Study @.ralph/specs/$FEATURE-implementation-plan.md for current tasks.
|
|
5
|
+
{{#if frameworkVariant}}For detailed architecture, see @{{appDir}}/.claude/CLAUDE.md{{/if}}
|
|
6
|
+
|
|
7
|
+
## Learnings
|
|
8
|
+
Read @.ralph/LEARNINGS.md for patterns and anti-patterns from previous iterations.
|
|
9
|
+
Apply relevant learnings to avoid repeating past mistakes.
|
|
10
|
+
|
|
11
|
+
## Performance
|
|
12
|
+
For data fetching, new components, or optimization tasks, reference @.ralph/guides/PERFORMANCE.md.
|
|
13
|
+
Key patterns: parallel fetches, direct imports, React.cache(), lazy loading.
|
|
14
|
+
|
|
15
|
+
## Search
|
|
16
|
+
- Use `mgrep "query"` for codebase searches (patterns, implementations, usages)
|
|
17
|
+
- Use Context7 MCP for library/framework documentation
|
|
18
|
+
- Search codebase before assuming something doesn't exist
|
|
19
|
+
|
|
20
|
+
## Task
|
|
21
|
+
Pick the next incomplete task from the implementation plan.
|
|
22
|
+
**Skip E2E tasks** (tasks starting with `E2E:`) - those are handled in a separate phase.
|
|
23
|
+
Implement it following the patterns in AGENTS.md.
|
|
24
|
+
Write tests for the implementation.
|
|
25
|
+
|
|
26
|
+
## Validation
|
|
27
|
+
After changes, ALL must pass:
|
|
28
|
+
1. Run: `cd {{appDir}} && {{lintCommand}} -- --fix`
|
|
29
|
+
2. Run: `cd {{appDir}} && {{typecheckCommand}}` (typecheck)
|
|
30
|
+
3. Run: `cd {{appDir}} && {{testCommand}}`
|
|
31
|
+
4. Run: `cd {{appDir}} && {{buildCommand}}`
|
|
32
|
+
|
|
33
|
+
If any validation fails, fix the issue before proceeding.
|
|
34
|
+
|
|
35
|
+
## Security Review
|
|
36
|
+
Before committing, review your changes against @.ralph/guides/SECURITY.md:
|
|
37
|
+
1. **Quick scan**: Input validation, injection prevention, auth checks, data exposure
|
|
38
|
+
2. **Run**: `cd {{appDir}} && {{packageManager}} audit` (check for vulnerable dependencies)
|
|
39
|
+
3. **Check**: `mcp__supabase__get_advisors` with type "security" (RLS policies)
|
|
40
|
+
4. **Red team**: Can auth be bypassed? Can other users' data be accessed?
|
|
41
|
+
|
|
42
|
+
Flag any security issues in the implementation plan and fix before committing.
|
|
43
|
+
|
|
44
|
+
## Design Quality Check
|
|
45
|
+
Before marking a UI task complete, verify against @.ralph/guides/FRONTEND.md:
|
|
46
|
+
1. Uses design tokens (no hard-coded colors like `#fff` or `rgb()`)
|
|
47
|
+
2. Has hover/focus/active states on interactive elements
|
|
48
|
+
3. Responsive on mobile (test at 375px width)
|
|
49
|
+
4. Empty/loading/error states handled
|
|
50
|
+
5. Charts have titles, tooltips, and legends (if applicable)
|
|
51
|
+
6. Consistent spacing using Tailwind scale
|
|
52
|
+
|
|
53
|
+
If any check fails, fix before committing.
|
|
54
|
+
|
|
55
|
+
## Completion
|
|
56
|
+
When ALL validations pass:
|
|
57
|
+
1. Update @.ralph/specs/$FEATURE-implementation-plan.md - mark task done with commit hash
|
|
58
|
+
2. `git -C {{appDir}} add -A`
|
|
59
|
+
3. `git -C {{appDir}} commit -m "type(scope): description"`
|
|
60
|
+
4. `git -C {{appDir}} push origin feat/$FEATURE`
|
|
61
|
+
|
|
62
|
+
## Learning Capture
|
|
63
|
+
If this iteration revealed something useful, append to @.ralph/LEARNINGS.md:
|
|
64
|
+
- A useful pattern -> Add under "## Patterns (What Works)"
|
|
65
|
+
- A mistake/issue -> Add under "## Anti-Patterns (What to Avoid)"
|
|
66
|
+
- Tool usage tip -> Add under "## Tool Usage"
|
|
67
|
+
- Codebase convention -> Add under "## Codebase Conventions"
|
|
68
|
+
|
|
69
|
+
Format: `- [YYYY-MM-DD] [$FEATURE] Brief description`
|
|
70
|
+
|
|
71
|
+
## Rules
|
|
72
|
+
- One task per iteration
|
|
73
|
+
- Tests are mandatory - no task is complete without tests
|
|
74
|
+
- Search codebase before assuming something doesn't exist
|
|
75
|
+
- If blocked, document in implementation plan and move to next task
|
|
76
|
+
- Use Supabase MCP for database operations
|
|
77
|
+
- Use PostHog MCP for analytics queries
|
|
@@ -0,0 +1,234 @@
|
|
|
1
|
+
## Context
|
|
2
|
+
Study @.ralph/AGENTS.md for commands and patterns.
|
|
3
|
+
Study @.ralph/specs/$FEATURE.md for feature specification.
|
|
4
|
+
Study @.ralph/specs/$FEATURE-implementation-plan.md for E2E test scenarios.
|
|
5
|
+
{{#if frameworkVariant}}For detailed architecture, see @{{appDir}}/.claude/CLAUDE.md{{/if}}
|
|
6
|
+
|
|
7
|
+
## Learnings
|
|
8
|
+
Read @.ralph/LEARNINGS.md for E2E patterns and anti-patterns.
|
|
9
|
+
Pay special attention to "E2E Pitfalls" section to avoid known issues.
|
|
10
|
+
|
|
11
|
+
## Prerequisites
|
|
12
|
+
Before E2E testing, verify:
|
|
13
|
+
1. Build passes: `cd {{appDir}} && {{buildCommand}}`
|
|
14
|
+
2. All unit tests pass: `cd {{appDir}} && {{testCommand}}`
|
|
15
|
+
3. Clear cache if issues: `rm -rf {{appDir}}/.next`
|
|
16
|
+
|
|
17
|
+
If either fails, fix issues before proceeding with E2E tests.
|
|
18
|
+
|
|
19
|
+
## Task
|
|
20
|
+
Execute automated E2E tests for the completed feature using Playwright MCP tools.
|
|
21
|
+
|
|
22
|
+
### Step 1: Check Dev Server
|
|
23
|
+
Verify dev server is running at http://localhost:3000. If not accessible, start it:
|
|
24
|
+
```bash
|
|
25
|
+
cd {{appDir}} && {{devCommand}} &
|
|
26
|
+
```
|
|
27
|
+
Wait ~10 seconds for server startup, then verify with a simple browser_navigate.
|
|
28
|
+
|
|
29
|
+
### Step 1.5: Seed Test Data (if needed)
|
|
30
|
+
|
|
31
|
+
Check if test scenarios require specific data volumes (e.g., pagination needs >10 rows).
|
|
32
|
+
|
|
33
|
+
**Seeding with Supabase MCP:**
|
|
34
|
+
```
|
|
35
|
+
mcp__supabase__execute_sql
|
|
36
|
+
query: "INSERT INTO table_name (survey_id, data, created_at)
|
|
37
|
+
SELECT '{survey_id}', '{"_test": true}'::jsonb, NOW() - (n || ' hours')::interval
|
|
38
|
+
FROM generate_series(1, 25) n;"
|
|
39
|
+
```
|
|
40
|
+
|
|
41
|
+
**Mark test data for cleanup:**
|
|
42
|
+
- Add `"_test": true` to JSON data columns
|
|
43
|
+
- Use unique utm_source: `e2e_${FEATURE}_${timestamp}`
|
|
44
|
+
|
|
45
|
+
**Cleanup after tests:**
|
|
46
|
+
```
|
|
47
|
+
mcp__supabase__execute_sql
|
|
48
|
+
query: "DELETE FROM table_name WHERE data->>'_test' = 'true';"
|
|
49
|
+
```
|
|
50
|
+
|
|
51
|
+
**If seeding is impractical:** Document in implementation plan that E2E was skipped but unit tests provide coverage.
|
|
52
|
+
|
|
53
|
+
### Step 2: Parse E2E Test Scenarios
|
|
54
|
+
Read E2E test scenarios from @.ralph/specs/$FEATURE-implementation-plan.md.
|
|
55
|
+
Each scenario is marked with `- [ ] E2E:` prefix and follows this format:
|
|
56
|
+
|
|
57
|
+
```
|
|
58
|
+
- [ ] E2E: [Scenario name]
|
|
59
|
+
- **URL:** [starting URL]
|
|
60
|
+
- **Preconditions:** [setup needed]
|
|
61
|
+
- **Steps:**
|
|
62
|
+
1. [Action] -> [expected result]
|
|
63
|
+
- **Verify:** [final assertion]
|
|
64
|
+
- **Database check:** [optional SQL]
|
|
65
|
+
```
|
|
66
|
+
|
|
67
|
+
### Step 3: Execute Each Scenario
|
|
68
|
+
For each E2E test scenario:
|
|
69
|
+
|
|
70
|
+
1. **Navigate** to starting URL:
|
|
71
|
+
```
|
|
72
|
+
mcp__plugin_playwright_playwright__browser_navigate
|
|
73
|
+
url: "http://localhost:3000/..."
|
|
74
|
+
```
|
|
75
|
+
|
|
76
|
+
2. **Capture page state** for element references:
|
|
77
|
+
```
|
|
78
|
+
mcp__plugin_playwright_playwright__browser_snapshot
|
|
79
|
+
```
|
|
80
|
+
This returns an accessibility tree with element refs (e.g., `button[3]`, `textbox[0]`).
|
|
81
|
+
|
|
82
|
+
3. **Execute actions** using refs from snapshot:
|
|
83
|
+
- Click: `browser_click` with element description and ref
|
|
84
|
+
- Type: `browser_type` with ref, text, and optionally `submit: true`
|
|
85
|
+
- Fill form: `browser_fill_form` for multiple fields
|
|
86
|
+
- Select: `browser_select_option` for dropdowns
|
|
87
|
+
- Wait: `browser_wait_for` with text to appear/disappear
|
|
88
|
+
|
|
89
|
+
4. **Verify results**:
|
|
90
|
+
- Call `browser_snapshot` to get current page state
|
|
91
|
+
- Check that expected text/elements are present in the snapshot
|
|
92
|
+
- Use `browser_wait_for` if async operations need time
|
|
93
|
+
|
|
94
|
+
5. **On failure**:
|
|
95
|
+
- Take screenshot: `browser_take_screenshot`
|
|
96
|
+
- Check console: `browser_console_messages` for JS errors
|
|
97
|
+
- Document failure details
|
|
98
|
+
|
|
99
|
+
### Step 4: Database Verification
|
|
100
|
+
For scenarios with database checks, use Supabase MCP:
|
|
101
|
+
```
|
|
102
|
+
mcp__plugin_supabase_supabase__execute_sql
|
|
103
|
+
project_id: [project ID]
|
|
104
|
+
query: "SELECT * FROM survey_responses WHERE ..."
|
|
105
|
+
```
|
|
106
|
+
|
|
107
|
+
Verify returned data matches expected state.
|
|
108
|
+
|
|
109
|
+
### Unique Test Data (for Parallel Execution)
|
|
110
|
+
When creating test data, use unique identifiers to avoid conflicts with other loops:
|
|
111
|
+
- Add feature-specific UTM params: `?utm_source=e2e_${FEATURE}_${timestamp}`
|
|
112
|
+
- Use unique names/emails: `test_${FEATURE}_${timestamp}@example.com`
|
|
113
|
+
- This ensures database queries find only this test's data
|
|
114
|
+
|
|
115
|
+
### Step 5: Report Results
|
|
116
|
+
Update @.ralph/specs/$FEATURE-implementation-plan.md for each scenario:
|
|
117
|
+
|
|
118
|
+
**Passed:**
|
|
119
|
+
```markdown
|
|
120
|
+
- [x] E2E: scenario name - PASSED
|
|
121
|
+
```
|
|
122
|
+
|
|
123
|
+
**Failed:**
|
|
124
|
+
```markdown
|
|
125
|
+
- [ ] E2E: scenario name - FAILED: [brief reason]
|
|
126
|
+
- Error: [what went wrong]
|
|
127
|
+
- Screenshot: [if captured]
|
|
128
|
+
- Fix needed: [suggested action]
|
|
129
|
+
```
|
|
130
|
+
|
|
131
|
+
## Playwright MCP Tool Reference
|
|
132
|
+
|
|
133
|
+
| Tool | Purpose | Key Parameters |
|
|
134
|
+
|------|---------|----------------|
|
|
135
|
+
| `browser_navigate` | Go to URL | `url` |
|
|
136
|
+
| `browser_snapshot` | Get page state (use for assertions) | - |
|
|
137
|
+
| `browser_click` | Click element | `element`, `ref` |
|
|
138
|
+
| `browser_type` | Type into element | `element`, `ref`, `text`, `submit` |
|
|
139
|
+
| `browser_fill_form` | Fill multiple fields | `fields[]` with name, type, ref, value |
|
|
140
|
+
| `browser_select_option` | Select dropdown | `element`, `ref`, `values[]` |
|
|
141
|
+
| `browser_wait_for` | Wait for text/time | `text`, `textGone`, `time` |
|
|
142
|
+
| `browser_take_screenshot` | Capture visual state | `filename` (optional) |
|
|
143
|
+
| `browser_console_messages` | Get JS console output | `level` (error/warning/info) |
|
|
144
|
+
| `browser_press_key` | Press keyboard key | `key` (e.g., "Enter", "Tab") |
|
|
145
|
+
| `browser_close` | Close browser/reset state | - |
|
|
146
|
+
|
|
147
|
+
## Assertion Patterns
|
|
148
|
+
|
|
149
|
+
### Text Verification
|
|
150
|
+
```
|
|
151
|
+
1. browser_snapshot -> get page content
|
|
152
|
+
2. Check snapshot output for expected text strings
|
|
153
|
+
3. If text not found, scenario fails
|
|
154
|
+
```
|
|
155
|
+
|
|
156
|
+
### Element State
|
|
157
|
+
```
|
|
158
|
+
1. browser_snapshot -> accessibility tree shows element states
|
|
159
|
+
2. Check for: enabled/disabled, checked/unchecked, visible
|
|
160
|
+
```
|
|
161
|
+
|
|
162
|
+
### URL Verification
|
|
163
|
+
```
|
|
164
|
+
1. After navigation/action, snapshot shows current URL
|
|
165
|
+
2. Verify URL contains expected path/params
|
|
166
|
+
```
|
|
167
|
+
|
|
168
|
+
### Database State
|
|
169
|
+
```
|
|
170
|
+
1. mcp__plugin_supabase_supabase__execute_sql with SELECT query
|
|
171
|
+
2. Verify row count, column values match expectations
|
|
172
|
+
```
|
|
173
|
+
|
|
174
|
+
## Browser State Management
|
|
175
|
+
|
|
176
|
+
- Use `browser_close` between unrelated scenarios to reset localStorage/cookies
|
|
177
|
+
- Keep browser open for scenarios that test state persistence (e.g., duplicate submission)
|
|
178
|
+
- Fresh browser state = clean localStorage, no prior submissions tracked
|
|
179
|
+
|
|
180
|
+
## Error Recovery
|
|
181
|
+
|
|
182
|
+
If a scenario fails:
|
|
183
|
+
1. Document the failure with specific error details
|
|
184
|
+
2. Note what fix is likely needed (code bug vs test spec issue)
|
|
185
|
+
3. Continue with remaining scenarios
|
|
186
|
+
4. At end, summary shows total passed/failed
|
|
187
|
+
|
|
188
|
+
Failures will trigger a fix iteration in the loop.
|
|
189
|
+
|
|
190
|
+
## Completion
|
|
191
|
+
|
|
192
|
+
When all scenarios are executed:
|
|
193
|
+
1. Update implementation plan with results for each scenario
|
|
194
|
+
2. Update the Implementation Summary status to `[PASSED]` if all passed
|
|
195
|
+
3. **Commit the updated implementation plan:**
|
|
196
|
+
```bash
|
|
197
|
+
git -C {{appDir}} add -A && git -C {{appDir}} commit -m "test($FEATURE): E2E tests passed via Playwright"
|
|
198
|
+
```
|
|
199
|
+
4. **Push to remote:**
|
|
200
|
+
```bash
|
|
201
|
+
git -C {{appDir}} push origin feat/$FEATURE
|
|
202
|
+
```
|
|
203
|
+
5. If all passed: signal ready for PR phase
|
|
204
|
+
6. If any failed: failures documented, loop will retry after fix iteration
|
|
205
|
+
|
|
206
|
+
## Troubleshooting
|
|
207
|
+
|
|
208
|
+
### UI Changes Not Visible
|
|
209
|
+
If code changes don't appear in the browser:
|
|
210
|
+
1. Stop the dev server
|
|
211
|
+
2. Clear cache: `rm -rf {{appDir}}/.next`
|
|
212
|
+
3. Restart: `cd {{appDir}} && {{devCommand}}`
|
|
213
|
+
4. Wait for full rebuild before testing
|
|
214
|
+
|
|
215
|
+
### Stale Data
|
|
216
|
+
- Clear browser storage: Use `browser_close` between scenarios
|
|
217
|
+
- Check Supabase for stale test data from previous runs
|
|
218
|
+
- Delete test data: `DELETE FROM table WHERE data->>'_test' = 'true'`
|
|
219
|
+
|
|
220
|
+
## Rules
|
|
221
|
+
- Always get a fresh `browser_snapshot` after actions before making assertions
|
|
222
|
+
- Use `browser_wait_for` when waiting for async operations (form submission, API calls)
|
|
223
|
+
- Take screenshots only on failures to avoid clutter
|
|
224
|
+
- Verify database state for data-mutation features
|
|
225
|
+
- Keep scenarios independent when possible
|
|
226
|
+
- Document failures clearly so fix iteration knows what to address
|
|
227
|
+
|
|
228
|
+
## Learning Capture
|
|
229
|
+
If E2E testing revealed issues worth remembering, append to @.ralph/LEARNINGS.md:
|
|
230
|
+
- Flaky test patterns -> Add under "## Anti-Patterns" > "E2E Pitfalls"
|
|
231
|
+
- Useful Playwright techniques -> Add under "## Tool Usage"
|
|
232
|
+
- Timing issues or race conditions -> Add under "## Anti-Patterns"
|
|
233
|
+
|
|
234
|
+
Format: `- [YYYY-MM-DD] [$FEATURE] Brief description`
|