codeninja 3.2.0 → 4.0.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/README.md +13 -1
- package/agent/database-agent.md +24 -1
- package/agent/nodejs-agent.md +79 -0
- package/cli.js +27 -7
- package/commands/audit.workflow.md +4 -1
- package/commands/db-create-table.workflow.md +1 -1
- package/commands/initialize-project.workflow.md +21 -0
- package/ide/antigravity/.agents/personas/database-architect.md +431 -153
- package/ide/antigravity/.agents/personas/global-orchestrator.md +202 -85
- package/ide/antigravity/.agents/personas/nodejs-backend.md +368 -133
- package/ide/antigravity/.agents/personas/reactjs-frontend.md +182 -101
- package/ide/antigravity/.agents/skills/api-builder/SKILL.md +58 -0
- package/ide/antigravity/.agents/skills/code-intelligence/SKILL.md +22 -0
- package/ide/antigravity/.agents/skills/database/SKILL.md +32 -0
- package/ide/antigravity/.agents/skills/mcp-and-context/SKILL.md +76 -82
- package/ide/antigravity/.agents/skills/reactjs/SKILL.md +36 -0
- package/ide/antigravity/.agents/workflows/codeninja-api.md +76 -83
- package/ide/antigravity/.agents/workflows/codeninja-audit.md +82 -44
- package/ide/antigravity/.agents/workflows/codeninja-db-create.md +107 -94
- package/ide/antigravity/.agents/workflows/codeninja-db-drop.md +89 -67
- package/ide/antigravity/.agents/workflows/codeninja-db-index.md +86 -54
- package/ide/antigravity/.agents/workflows/codeninja-db-modify.md +126 -68
- package/ide/antigravity/.agents/workflows/codeninja-db-seed.md +87 -59
- package/ide/antigravity/.agents/workflows/codeninja-db-sync.md +77 -41
- package/ide/antigravity/.agents/workflows/codeninja-debug.md +35 -21
- package/ide/antigravity/.agents/workflows/codeninja-design.md +49 -35
- package/ide/antigravity/.agents/workflows/codeninja-explain.md +41 -20
- package/ide/antigravity/.agents/workflows/codeninja-init.md +479 -289
- package/ide/antigravity/.agents/workflows/codeninja-integrate-api.md +253 -136
- package/ide/antigravity/.agents/workflows/codeninja-modularize.md +250 -132
- package/ide/antigravity/.agents/workflows/codeninja-optimize.md +71 -29
- package/ide/antigravity/.agents/workflows/codeninja-refactor.md +50 -42
- package/ide/antigravity/.agents/workflows/codeninja-review.md +38 -21
- package/ide/antigravity/.agents/workflows/codeninja-sync.md +922 -141
- package/ide/antigravity/.agents/workflows/codeninja-test.md +34 -49
- package/ide/antigravity/.agents/workflows/codeninja-validate-page.md +449 -151
- package/ide/claude-code/.claude/CLAUDE.md +99 -0
- package/ide/claude-code/.claude/agents/database-agent.md +535 -0
- package/ide/claude-code/.claude/agents/nodejs-agent.md +493 -0
- package/ide/claude-code/.claude/agents/reactjs-agent.md +267 -0
- package/ide/claude-code/.claude/commands/codeninja-api.md +104 -0
- package/ide/claude-code/.claude/commands/codeninja-audit.md +119 -0
- package/ide/claude-code/.claude/commands/codeninja-db-create.md +138 -0
- package/ide/claude-code/.claude/commands/codeninja-db-drop.md +109 -0
- package/ide/claude-code/.claude/commands/codeninja-db-index.md +103 -0
- package/ide/claude-code/.claude/commands/codeninja-db-modify.md +165 -0
- package/ide/claude-code/.claude/commands/codeninja-db-seed.md +104 -0
- package/ide/claude-code/.claude/commands/codeninja-db-sync.md +106 -0
- package/ide/claude-code/.claude/commands/codeninja-debug.md +99 -0
- package/ide/claude-code/.claude/commands/codeninja-design.md +68 -0
- package/ide/claude-code/.claude/commands/codeninja-explain.md +61 -0
- package/ide/claude-code/.claude/commands/codeninja-init.md +529 -0
- package/ide/claude-code/.claude/commands/codeninja-integrate-api.md +453 -0
- package/ide/claude-code/.claude/commands/codeninja-modularize.md +334 -0
- package/ide/claude-code/.claude/commands/codeninja-optimize.md +129 -0
- package/ide/claude-code/.claude/commands/codeninja-refactor.md +76 -0
- package/ide/claude-code/.claude/commands/codeninja-review.md +87 -0
- package/ide/claude-code/.claude/commands/codeninja-sync.md +964 -0
- package/ide/claude-code/.claude/commands/codeninja-test.md +45 -0
- package/ide/claude-code/.claude/commands/codeninja-validate-page.md +548 -0
- package/ide/cursor/.cursor/rules/01-global-orchestrator.mdc +12 -13
- package/ide/cursor/.cursor/rules/02-mcp-and-context.mdc +47 -31
- package/ide/cursor/.cursor/rules/03-api-builder.mdc +32 -110
- package/ide/cursor/.cursor/rules/04-nodejs-generation.mdc +58 -0
- package/ide/cursor/.cursor/rules/05-database.mdc +54 -0
- package/ide/cursor/.cursor/rules/06-reactjs.mdc +36 -0
- package/ide/cursor/.cursor/rules/07-reactjs-generation.mdc +49 -0
- package/ide/cursor/.cursor/rules/08-code-intelligence.mdc +56 -0
- package/ide/cursor/.cursor/rules/09-workflow-steps.mdc +53 -0
- package/ide/vscode/.github/copilot-instructions.md +67 -382
- package/ide/vscode/.vscode/instructions/code-intelligence.instructions.md +58 -0
- package/ide/vscode/.vscode/instructions/database.instructions.md +55 -0
- package/ide/vscode/.vscode/instructions/nodejs.instructions.md +77 -0
- package/ide/vscode/.vscode/instructions/reactjs.instructions.md +42 -0
- package/package.json +2 -2
- package/tasks/ask-hashing-library.task.md +31 -0
- package/tasks/ask-language-type.task.md +26 -0
- package/tasks/ask-new-module-name.task.md +13 -0
- package/tasks/ask-new-service-name.task.md +13 -0
- package/tasks/ask-old-module-name.task.md +15 -0
- package/tasks/ask-old-service-name.task.md +13 -0
- package/tasks/ask-orm-type.task.md +26 -0
- package/tasks/collect-seed-data.task.md +19 -0
- package/tasks/generate-app.task.md +42 -0
- package/tasks/generate-common.task.md +13 -0
- package/tasks/generate-constants.task.md +13 -0
- package/tasks/generate-database.task.md +32 -0
- package/tasks/generate-encryption.task.md +28 -0
- package/tasks/generate-fast-defaults.task.md +7 -0
- package/tasks/generate-hashing.task.md +180 -0
- package/tasks/generate-headerValidator.task.md +13 -0
- package/tasks/generate-ioRedis.task.md +20 -0
- package/tasks/generate-language-en.task.md +12 -0
- package/tasks/generate-logging.task.md +12 -0
- package/tasks/generate-model.task.md +74 -6
- package/tasks/generate-notification.task.md +12 -0
- package/tasks/generate-package-json.task.md +69 -0
- package/tasks/generate-prisma-client.task.md +56 -0
- package/tasks/generate-prisma-schema.task.md +71 -0
- package/tasks/generate-rateLimiter.task.md +20 -0
- package/tasks/generate-readme.task.md +24 -0
- package/tasks/generate-response.task.md +27 -0
- package/tasks/generate-route-manager.task.md +32 -0
- package/tasks/generate-route.task.md +37 -0
- package/tasks/generate-swagger.task.md +8 -0
- package/tasks/generate-template.task.md +12 -0
- package/tasks/generate-tsconfig.task.md +38 -0
- package/tasks/generate-validator.task.md +31 -0
- package/ide/cursor/.cursor/rules/04-database.mdc +0 -90
- package/ide/cursor/.cursor/rules/05-reactjs.mdc +0 -147
- package/ide/cursor/.cursor/rules/06-code-intelligence.mdc +0 -112
|
@@ -1,115 +1,162 @@
|
|
|
1
|
+
This workflow runs when user invokes /codeninja:integrate-api
|
|
2
|
+
|
|
1
3
|
---
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
skills: [mcp-and-context, reactjs, api-builder]
|
|
4
|
+
type: workflow
|
|
5
|
+
name: integrate-api
|
|
5
6
|
description: >
|
|
6
|
-
|
|
7
|
-
through apiHandler.js and apiClient.js.
|
|
8
|
-
|
|
7
|
+
Wires a ReactJS page's forms and action buttons to backend API calls
|
|
8
|
+
through apiHandler.js and apiClient.js. Creates or updates submit
|
|
9
|
+
handler functions, adds loading states, and wires success/error
|
|
10
|
+
responses back to the UI. Never touches validation logic or component
|
|
11
|
+
layout — API integration only.
|
|
9
12
|
---
|
|
10
13
|
|
|
11
|
-
#
|
|
14
|
+
# Workflow: @integrate-api
|
|
12
15
|
|
|
13
|
-
##
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
16
|
+
## Goal
|
|
17
|
+
Connect the frontend page to the backend. After this workflow runs,
|
|
18
|
+
every form submit and action button on the target page calls the
|
|
19
|
+
correct API handler function, handles the loading state, and processes
|
|
20
|
+
the response correctly.
|
|
17
21
|
|
|
18
22
|
## Rules
|
|
19
|
-
- Target
|
|
23
|
+
- Target one specific page per run
|
|
20
24
|
- NEVER modify layout, CSS, or validation logic
|
|
21
|
-
- ALWAYS use `apiHandler.js` for API calls — never call `axiosClient`
|
|
22
|
-
|
|
25
|
+
- ALWAYS use `apiHandler.js` for API calls — never call `axiosClient`
|
|
26
|
+
directly from a page component
|
|
27
|
+
- ALWAYS add handler functions to `apiHandler.js` if the needed function
|
|
28
|
+
does not already exist there — never inline API calls in the page
|
|
23
29
|
- NEVER hardcode API endpoints in page files
|
|
24
30
|
- ONE confirmation before any file is written
|
|
25
|
-
- After writing files →
|
|
31
|
+
- After writing files → run task: `write-context`
|
|
26
32
|
|
|
27
33
|
---
|
|
28
34
|
|
|
29
|
-
##
|
|
35
|
+
## Step-by-Step Execution
|
|
36
|
+
|
|
37
|
+
---
|
|
30
38
|
|
|
31
39
|
### Phase 1 — Target Selection
|
|
32
40
|
|
|
33
|
-
|
|
34
|
-
|
|
41
|
+
1. Run task: `ask-react-target-service`
|
|
42
|
+
Stores: `context.current_action.service_name`
|
|
35
43
|
|
|
36
|
-
|
|
37
|
-
|
|
44
|
+
2. Run task: `ask-page-path`
|
|
45
|
+
Stores: `context.current_action.page_path`
|
|
46
|
+
Stores: `context.current_action.page_name`
|
|
38
47
|
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
- Store: `context.current_action.api_integration_scope`
|
|
43
|
-
- If specific → ask: "Which form or button?" → Store: `context.current_action.api_integration_target`
|
|
48
|
+
3. Run task: `ask-api-integration-scope`
|
|
49
|
+
Stores: `context.current_action.api_integration_scope`
|
|
50
|
+
If scope == "specific" → also stores `context.current_action.api_integration_target`
|
|
44
51
|
|
|
45
52
|
---
|
|
46
53
|
|
|
47
54
|
### Phase 2 — Read Service Context
|
|
48
55
|
|
|
49
56
|
Read from context:
|
|
50
|
-
- `context.
|
|
51
|
-
- `context.
|
|
57
|
+
- `context.current_action.service_name` → the ReactJS service
|
|
58
|
+
- `context.services[<service_name>].linked_service` → the backend NodeJS service name
|
|
59
|
+
- `context.api_routes` filtered by the linked NodeJS service → available API routes
|
|
52
60
|
|
|
53
61
|
Read from disk:
|
|
54
|
-
- Full content of `context.current_action.page_path` (target page)
|
|
55
|
-
- Full content of `src/api/apiHandler.js`
|
|
56
|
-
- Full content of `src/api/apiClient.js` (read-only reference)
|
|
62
|
+
- Full content of `context.current_action.page_path` (the target page)
|
|
63
|
+
- Full content of `src/api/apiHandler.js` in the target service
|
|
64
|
+
- Full content of `src/api/apiClient.js` in the target service (read-only reference)
|
|
57
65
|
|
|
58
66
|
---
|
|
59
67
|
|
|
60
68
|
### Phase 3 — Scan the Page for Integration Points
|
|
61
69
|
|
|
70
|
+
Read the page file and identify every place that could trigger an API call:
|
|
71
|
+
|
|
62
72
|
#### 3a — Forms
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
-
|
|
66
|
-
|
|
73
|
+
|
|
74
|
+
For each `<form>` element found:
|
|
75
|
+
- Note the form's apparent purpose (login, register, search, update
|
|
76
|
+
profile, etc.) — infer from field names, labels, heading text nearby
|
|
77
|
+
- Check if an `onSubmit` handler is already connected:
|
|
78
|
+
- `<form onSubmit={...}>` → handler exists, note the function name
|
|
79
|
+
- No `onSubmit` → no handler yet
|
|
80
|
+
- Check if a submit button exists: `<button type="submit">` or
|
|
81
|
+
`<input type="submit">`
|
|
82
|
+
- Note whether the form already imports anything from `apiHandler.js`
|
|
67
83
|
|
|
68
84
|
#### 3b — Action Buttons
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
-
|
|
72
|
-
|
|
85
|
+
|
|
86
|
+
For each `<button>` or clickable element that is NOT a submit button:
|
|
87
|
+
- Check if an `onClick` handler is connected
|
|
88
|
+
- Infer the action from button text or aria-label:
|
|
89
|
+
- "Delete", "Remove" → delete action
|
|
90
|
+
- "Edit", "Update" → update action
|
|
91
|
+
- "Save" → save/create action
|
|
92
|
+
- "Logout", "Sign out" → logout action
|
|
93
|
+
- "Load more", "Next page" → pagination/fetch action
|
|
94
|
+
- "Export", "Download" → export action
|
|
95
|
+
- "Approve", "Reject" → status change action
|
|
96
|
+
- Note if the handler already contains an API call
|
|
73
97
|
|
|
74
98
|
#### 3c — Existing API Calls
|
|
75
|
-
Detect any existing API calls:
|
|
76
|
-
- Imports from `apiHandler.js` (existing — note them)
|
|
77
|
-
- Direct `axiosClient` calls (flag — should be moved to apiHandler)
|
|
78
|
-
- `fetch(` or `axios.` direct calls (flag — should be moved)
|
|
79
99
|
|
|
80
|
-
|
|
100
|
+
Detect any API calls already in the file:
|
|
101
|
+
- Imports from `apiHandler.js`
|
|
102
|
+
- `axiosClient` direct calls (flag these — they should be moved to apiHandler)
|
|
103
|
+
- `fetch(` or `axios.` calls (flag — should be moved to apiHandler)
|
|
104
|
+
|
|
105
|
+
If scope == "specific":
|
|
106
|
+
Apply the same scan but focus only on the form or action matching
|
|
107
|
+
`context.current_action.api_integration_target`. Other forms/buttons
|
|
108
|
+
are noted but not modified.
|
|
81
109
|
|
|
82
110
|
---
|
|
83
111
|
|
|
84
112
|
### Phase 4 — Match Forms to API Routes
|
|
85
113
|
|
|
86
|
-
For each integration point, determine which API route it
|
|
114
|
+
For each integration point found, determine which backend API route it
|
|
115
|
+
should call. Use this priority:
|
|
116
|
+
|
|
117
|
+
1. **Exact match** — an `apiHandler.js` function already exists for
|
|
118
|
+
this purpose (e.g. `webLogin` for a login form). Use it as-is.
|
|
87
119
|
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
new handler function will be added to `apiHandler.js`
|
|
91
|
-
3. **No match** — no suitable route exists yet → scaffold with TODO placeholder
|
|
120
|
+
2. **Route match** — a route exists in `context.api_routes` for the
|
|
121
|
+
linked backend service that matches the form's apparent purpose.
|
|
122
|
+
A new handler function will be added to `apiHandler.js` for it.
|
|
92
123
|
|
|
93
|
-
|
|
124
|
+
3. **No match** — no suitable route exists yet in either place.
|
|
125
|
+
The integration plan will note this as a gap. The form's submit
|
|
126
|
+
handler will be scaffolded with a `// TODO: connect to API` comment
|
|
127
|
+
and a placeholder structure so the page is functional once the
|
|
128
|
+
route is added. Do NOT create a route in the backend — that is
|
|
129
|
+
`@create-api`'s job.
|
|
130
|
+
|
|
131
|
+
For each match or gap, record:
|
|
132
|
+
`{ form_purpose, handler_function_name, route_path, route_method,
|
|
133
|
+
match_type: "existing_handler" | "new_handler" | "no_route" }`
|
|
94
134
|
|
|
95
135
|
---
|
|
96
136
|
|
|
97
137
|
### Phase 5 — Design the Integration
|
|
98
138
|
|
|
99
|
-
For each integration point:
|
|
139
|
+
For each integration point, design what needs to be generated:
|
|
140
|
+
|
|
141
|
+
#### 5a — State requirements
|
|
100
142
|
|
|
101
|
-
|
|
102
|
-
- `loading` state — boolean, false by default
|
|
103
|
-
- `error` state — string or null
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
-
|
|
107
|
-
|
|
108
|
-
-
|
|
143
|
+
Every API call needs at minimum:
|
|
144
|
+
- `loading` state — boolean, `false` by default
|
|
145
|
+
- `error` state — string or null, for displaying API error messages
|
|
146
|
+
to the user
|
|
147
|
+
- Response data state — depends on the form type:
|
|
148
|
+
- Auth forms (login/register) → no response data state needed
|
|
149
|
+
(session is stored by apiHandler)
|
|
150
|
+
- List/search forms → `data` state (array, `[]` default)
|
|
151
|
+
- Single-item fetch → `item` state (object, `null` default)
|
|
152
|
+
- Delete/update → may use a list refresh or a redirect
|
|
109
153
|
|
|
110
|
-
|
|
154
|
+
Identify existing state in the page to avoid duplicates. Only add
|
|
155
|
+
state that does not already exist.
|
|
111
156
|
|
|
112
|
-
|
|
157
|
+
#### 5b — Submit handler pattern
|
|
158
|
+
|
|
159
|
+
**Auth / destructive action pattern (login, delete, logout):**
|
|
113
160
|
```jsx
|
|
114
161
|
const handle[Action] = async (e) => {
|
|
115
162
|
e?.preventDefault();
|
|
@@ -118,14 +165,15 @@ const handle[Action] = async (e) => {
|
|
|
118
165
|
const res = await [handlerFunction]({ ...formData });
|
|
119
166
|
setLoading(false);
|
|
120
167
|
if (res?.code === 1) {
|
|
121
|
-
navigate
|
|
168
|
+
// success — navigate or show confirmation
|
|
169
|
+
navigate('/dashboard'); // use react-router useNavigate
|
|
122
170
|
} else {
|
|
123
171
|
setError(res?.message || 'Something went wrong. Please try again.');
|
|
124
172
|
}
|
|
125
173
|
};
|
|
126
174
|
```
|
|
127
175
|
|
|
128
|
-
**Data fetch / load (get list, get details):**
|
|
176
|
+
**Data fetch / load pattern (get list, get details):**
|
|
129
177
|
```jsx
|
|
130
178
|
const fetch[Resource] = async () => {
|
|
131
179
|
setLoading(true);
|
|
@@ -138,10 +186,11 @@ const fetch[Resource] = async () => {
|
|
|
138
186
|
setError(res?.message || 'Failed to load data. Please try again.');
|
|
139
187
|
}
|
|
140
188
|
};
|
|
141
|
-
// Also add: useEffect(() => { fetch[Resource](); }, []);
|
|
142
189
|
```
|
|
190
|
+
Also add a `useEffect(() => { fetch[Resource](); }, [])` call to
|
|
191
|
+
load data on component mount if appropriate.
|
|
143
192
|
|
|
144
|
-
**Create / Update (form submit):**
|
|
193
|
+
**Create / Update pattern (form submit):**
|
|
145
194
|
```jsx
|
|
146
195
|
const handle[Action] = async (e) => {
|
|
147
196
|
e?.preventDefault();
|
|
@@ -150,34 +199,72 @@ const handle[Action] = async (e) => {
|
|
|
150
199
|
const res = await [handlerFunction](formData);
|
|
151
200
|
setLoading(false);
|
|
152
201
|
if (res?.code === 1) {
|
|
202
|
+
// success — show message or reset form
|
|
153
203
|
setSuccessMsg(res?.message || '[Action] successful.');
|
|
154
|
-
resetForm();
|
|
204
|
+
resetForm(); // only if a form reset function exists
|
|
155
205
|
} else {
|
|
156
206
|
setError(res?.message || 'Something went wrong. Please try again.');
|
|
157
207
|
}
|
|
158
208
|
};
|
|
159
209
|
```
|
|
160
210
|
|
|
161
|
-
#### Loading feedback
|
|
211
|
+
#### 5c — Loading state feedback
|
|
212
|
+
|
|
213
|
+
Add a `disabled={loading}` prop to the submit button or action trigger.
|
|
214
|
+
Also add visual feedback text inside the button:
|
|
162
215
|
```jsx
|
|
163
216
|
<button type="submit" disabled={loading}>
|
|
164
217
|
{loading ? 'Please wait...' : '[Original Button Text]'}
|
|
165
218
|
</button>
|
|
166
219
|
```
|
|
167
220
|
|
|
168
|
-
#### Error display
|
|
221
|
+
#### 5d — Error display
|
|
222
|
+
|
|
223
|
+
Add an error display block just above the submit button:
|
|
169
224
|
```jsx
|
|
170
225
|
{error && <p className={styles.apiError}>{error}</p>}
|
|
171
226
|
```
|
|
172
227
|
|
|
173
|
-
|
|
228
|
+
Add to the page's `.module.css`:
|
|
229
|
+
```css
|
|
230
|
+
.apiError {
|
|
231
|
+
color: #dc3545;
|
|
232
|
+
font-size: 0.875rem;
|
|
233
|
+
margin-bottom: 0.75rem;
|
|
234
|
+
padding: 0.5rem 0.75rem;
|
|
235
|
+
background-color: #fff5f5;
|
|
236
|
+
border: 1px solid #f5c6cb;
|
|
237
|
+
border-radius: 4px;
|
|
238
|
+
}
|
|
239
|
+
```
|
|
240
|
+
|
|
241
|
+
#### 5e — Success feedback (for non-navigating actions)
|
|
242
|
+
|
|
243
|
+
If the action does not navigate away after success, add a success
|
|
244
|
+
message state and display:
|
|
245
|
+
```jsx
|
|
246
|
+
const [successMsg, setSuccessMsg] = React.useState('');
|
|
247
|
+
```
|
|
174
248
|
```jsx
|
|
175
249
|
{successMsg && <p className={styles.successMsg}>{successMsg}</p>}
|
|
176
250
|
```
|
|
251
|
+
```css
|
|
252
|
+
.successMsg {
|
|
253
|
+
color: #155724;
|
|
254
|
+
font-size: 0.875rem;
|
|
255
|
+
margin-bottom: 0.75rem;
|
|
256
|
+
padding: 0.5rem 0.75rem;
|
|
257
|
+
background-color: #d4edda;
|
|
258
|
+
border: 1px solid #c3e6cb;
|
|
259
|
+
border-radius: 4px;
|
|
260
|
+
}
|
|
261
|
+
```
|
|
177
262
|
|
|
178
263
|
---
|
|
179
264
|
|
|
180
|
-
### Phase 6 — Show Integration Plan
|
|
265
|
+
### Phase 6 — Build and Show Integration Plan
|
|
266
|
+
|
|
267
|
+
Display the integration plan before writing anything:
|
|
181
268
|
|
|
182
269
|
```
|
|
183
270
|
┌──────────────────────────────────────────────────────┐
|
|
@@ -190,40 +277,48 @@ const handle[Action] = async (e) => {
|
|
|
190
277
|
│ INTEGRATIONS │
|
|
191
278
|
│ │
|
|
192
279
|
│ ① Login Form → webLogin() │
|
|
193
|
-
│ Route
|
|
194
|
-
│ Handler
|
|
195
|
-
│ State add: loading, error
|
|
196
|
-
│ Pattern
|
|
280
|
+
│ Route : POST /login │
|
|
281
|
+
│ Handler : webLogin (already in apiHandler.js) │
|
|
282
|
+
│ State add : loading, error │
|
|
283
|
+
│ Pattern : auth/destructive │
|
|
197
284
|
│ On success: navigate('/dashboard') │
|
|
198
285
|
│ │
|
|
199
286
|
│ ② Delete Button → deleteUser() │
|
|
200
|
-
│ Route
|
|
201
|
-
│ Handler
|
|
202
|
-
│
|
|
203
|
-
│
|
|
287
|
+
│ Route : DELETE /users/:id │
|
|
288
|
+
│ Handler : deleteUser (NEW — will add to │
|
|
289
|
+
│ apiHandler.js) │
|
|
290
|
+
│ State add : deleteLoading, deleteError │
|
|
291
|
+
│ Pattern : destructive │
|
|
204
292
|
│ On success: refresh user list │
|
|
205
293
|
├──────────────────────────────────────────────────────┤
|
|
206
|
-
│ GAPS (no
|
|
207
|
-
│ ③ Export CSV Button — no route
|
|
208
|
-
│ Will add TODO placeholder
|
|
294
|
+
│ GAPS (no matching route yet) │
|
|
295
|
+
│ ③ Export CSV Button — no backend route for this yet │
|
|
296
|
+
│ Will add a TODO placeholder │
|
|
209
297
|
├──────────────────────────────────────────────────────┤
|
|
210
298
|
│ FILES TO MODIFY │
|
|
211
|
-
│ → src/pages/[PageName]/index.jsx
|
|
212
|
-
│ → src/pages/[PageName]/[PageName].module.css
|
|
213
|
-
│ → src/api/apiHandler.js (
|
|
299
|
+
│ → src/pages/[PageName]/index.jsx │
|
|
300
|
+
│ → src/pages/[PageName]/[PageName].module.css │
|
|
301
|
+
│ → src/api/apiHandler.js (add deleteUser function) │
|
|
214
302
|
└──────────────────────────────────────────────────────┘
|
|
215
303
|
```
|
|
216
304
|
|
|
217
|
-
Ask
|
|
305
|
+
Ask exactly this question:
|
|
306
|
+
"Apply this integration plan? (yes / no / adjust)"
|
|
307
|
+
|
|
308
|
+
- If yes → proceed to Phase 7
|
|
309
|
+
- If no → abort. Nothing is written.
|
|
310
|
+
- If adjust → ask what to change (different handler, different on-success
|
|
311
|
+
action, skip an integration point). Apply and re-display.
|
|
218
312
|
|
|
219
313
|
---
|
|
220
314
|
|
|
221
315
|
### Phase 7 — Apply Integration
|
|
222
316
|
|
|
223
|
-
#### 7a — Update apiHandler.js (new functions
|
|
317
|
+
#### 7a — Update apiHandler.js (if new functions needed)
|
|
318
|
+
|
|
319
|
+
For each integration with `match_type == "new_handler"`:
|
|
320
|
+
Surgically append to `src/api/apiHandler.js`:
|
|
224
321
|
|
|
225
|
-
For each `match_type == "new_handler"`:
|
|
226
|
-
Append to `src/api/apiHandler.js`:
|
|
227
322
|
```jsx
|
|
228
323
|
/**
|
|
229
324
|
* [Route description from context.api_routes or inferred].
|
|
@@ -232,94 +327,100 @@ Append to `src/api/apiHandler.js`:
|
|
|
232
327
|
* @returns {Promise<Object>} API response.
|
|
233
328
|
*/
|
|
234
329
|
export async function [functionName](data) {
|
|
235
|
-
const res = await axiosClient.
|
|
330
|
+
const res = await axiosClient.post('[route_path]', data);
|
|
236
331
|
return res;
|
|
237
332
|
}
|
|
238
333
|
```
|
|
239
|
-
Use correct method: `.get`, `.post`, `.put`, `.patch`, `.delete`.
|
|
240
|
-
For DELETE/GET with ID: `axiosClient.delete(\`/users/${data.id}\`)`
|
|
241
334
|
|
|
242
|
-
|
|
335
|
+
Use the correct HTTP method — `axiosClient.get`, `.post`, `.put`,
|
|
336
|
+
`.patch`, `.delete` — matching the route method.
|
|
337
|
+
|
|
338
|
+
For DELETE or GET with ID: use template string for the path:
|
|
339
|
+
```jsx
|
|
340
|
+
const res = await axiosClient.delete(`/users/${data.id}`);
|
|
341
|
+
```
|
|
342
|
+
|
|
343
|
+
For gaps (`match_type == "no_route"`):
|
|
243
344
|
```jsx
|
|
244
345
|
/**
|
|
245
|
-
* TODO: Connect to backend route once created via
|
|
346
|
+
* TODO: Connect to backend route once created via @create-api.
|
|
347
|
+
*
|
|
348
|
+
* @param {Object} data - Request payload.
|
|
349
|
+
* @returns {Promise<Object>} API response.
|
|
246
350
|
*/
|
|
247
351
|
export async function [functionName](data) {
|
|
352
|
+
// TODO: Replace with actual route when backend is ready.
|
|
353
|
+
// Suggested: POST /[suggested_path]
|
|
248
354
|
console.warn('[functionName] is not yet connected to a backend route.');
|
|
249
355
|
return { code: 0, message: 'API not connected yet.' };
|
|
250
356
|
}
|
|
251
357
|
```
|
|
252
358
|
|
|
253
|
-
#### 7b — Update the page file
|
|
359
|
+
#### 7b — Update the page file
|
|
360
|
+
|
|
361
|
+
Read the current page file. Apply all changes surgically:
|
|
254
362
|
|
|
255
|
-
1. Add imports for
|
|
363
|
+
1. **Add imports** for apiHandler functions (only the new ones):
|
|
256
364
|
```jsx
|
|
257
365
|
import { webLogin, deleteUser } from '../../api/apiHandler';
|
|
258
366
|
```
|
|
259
|
-
|
|
367
|
+
Also add `useNavigate` from react-router-dom if any handler navigates:
|
|
260
368
|
```jsx
|
|
261
369
|
import { useNavigate } from 'react-router-dom';
|
|
262
370
|
```
|
|
263
371
|
|
|
264
|
-
2. Add state declarations inside component:
|
|
372
|
+
2. **Add state declarations** inside the component function:
|
|
265
373
|
```jsx
|
|
266
374
|
const [loading, setLoading] = React.useState(false);
|
|
267
375
|
const [error, setError] = React.useState(null);
|
|
268
|
-
const navigate = useNavigate(); // if navigate is used
|
|
269
376
|
```
|
|
377
|
+
Add `const navigate = useNavigate();` if navigate is used.
|
|
270
378
|
|
|
271
|
-
3. Add handler functions
|
|
272
|
-
|
|
379
|
+
3. **Add or update handler functions** inside the component:
|
|
380
|
+
Insert each handler function just before the return statement.
|
|
381
|
+
If a handler already exists (from validation or prior code) →
|
|
382
|
+
add only the API call logic inside it, not a new function.
|
|
273
383
|
|
|
274
|
-
4. Wire form
|
|
275
|
-
- `<form onSubmit={
|
|
276
|
-
|
|
384
|
+
4. **Wire the form's onSubmit / button's onClick**:
|
|
385
|
+
- If `<form onSubmit={existing}>` → rename existing handler and
|
|
386
|
+
call it inside the new handler (after the API call succeeds)
|
|
387
|
+
- If no onSubmit → add `onSubmit={handle[Action]}`
|
|
388
|
+
- If button has no onClick → add `onClick={handle[Action]}`
|
|
277
389
|
|
|
278
|
-
5. Add
|
|
390
|
+
5. **Add loading state to buttons**:
|
|
391
|
+
Locate each submit button / action button. Add `disabled={loading}`
|
|
392
|
+
and the conditional button text as designed in Phase 5c.
|
|
279
393
|
|
|
280
|
-
6. Add error and success display elements
|
|
394
|
+
6. **Add error and success display elements**:
|
|
395
|
+
Place the error `<p>` above the submit button.
|
|
396
|
+
Place the success `<p>` below the submit button (for non-nav actions).
|
|
281
397
|
|
|
282
|
-
7. Add
|
|
398
|
+
7. **Add useEffect for data fetching** if applicable (Phase 5b).
|
|
283
399
|
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
```css
|
|
287
|
-
.apiError {
|
|
288
|
-
color: #dc3545;
|
|
289
|
-
font-size: 0.875rem;
|
|
290
|
-
margin-bottom: 0.75rem;
|
|
291
|
-
padding: 0.5rem 0.75rem;
|
|
292
|
-
background-color: #fff5f5;
|
|
293
|
-
border: 1px solid #f5c6cb;
|
|
294
|
-
border-radius: 4px;
|
|
295
|
-
}
|
|
400
|
+
> **Multi-agent:** Delegate to `reactjs-frontend` via Task invocation for parallel execution.
|
|
401
|
+
> Read `.codeninja/tasks/` before applying API integration changes.
|
|
296
402
|
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
padding: 0.5rem 0.75rem;
|
|
302
|
-
background-color: #d4edda;
|
|
303
|
-
border: 1px solid #c3e6cb;
|
|
304
|
-
border-radius: 4px;
|
|
305
|
-
}
|
|
306
|
-
```
|
|
403
|
+
#### 7c — Update the page's CSS module
|
|
404
|
+
|
|
405
|
+
Add `.apiError` and `.successMsg` classes to the page's `.module.css`
|
|
406
|
+
if they are not already there. Do not overwrite existing definitions.
|
|
307
407
|
|
|
308
408
|
---
|
|
309
409
|
|
|
310
|
-
### Phase 8 —
|
|
410
|
+
### Phase 8 — Write Context and Report
|
|
311
411
|
|
|
312
|
-
|
|
412
|
+
Run task: `write-context` with:
|
|
313
413
|
- Append to `context.services[<service_name>].integrated_pages`:
|
|
314
|
-
`{ page, integrations: [{ form_purpose, handler, route }], timestamp: ISO now }`
|
|
414
|
+
`{ page, integrations: [list of { form_purpose, handler, route }], timestamp: ISO now }`
|
|
315
415
|
- Set `last_command` = "integrate-api"
|
|
316
|
-
- Append to `change_log
|
|
416
|
+
- Append to top-level `change_log`:
|
|
417
|
+
`{ timestamp, command: "integrate-api", action: "Wired [n] API calls in [page]", affected_files: [...] }`
|
|
418
|
+
- After write-context → call MCP tool `context_clear_scratchpad` with keys: ["current_action"]
|
|
317
419
|
|
|
318
|
-
|
|
420
|
+
Display completion report:
|
|
319
421
|
|
|
320
|
-
**Step 3.** Show completion report:
|
|
321
422
|
```
|
|
322
|
-
|
|
423
|
+
@integrate-api Complete
|
|
323
424
|
─────────────────────────────────────────
|
|
324
425
|
Page : [page_name]
|
|
325
426
|
Integrations : [n] connected, [n] placeholders
|
|
@@ -330,7 +431,23 @@ Integrations : [n] connected, [n] placeholders
|
|
|
330
431
|
─────────────────────────────────────────
|
|
331
432
|
[If gaps exist:]
|
|
332
433
|
⚠ [n] action(s) have no backend route yet.
|
|
333
|
-
Placeholders added
|
|
334
|
-
then re-run
|
|
434
|
+
Placeholders added — run @create-api to scaffold the backend routes,
|
|
435
|
+
then re-run @integrate-api to connect them.
|
|
335
436
|
─────────────────────────────────────────
|
|
336
437
|
```
|
|
438
|
+
|
|
439
|
+
Run task: `show-final-summary`
|
|
440
|
+
|
|
441
|
+
---
|
|
442
|
+
|
|
443
|
+
## What This Workflow Does NOT Do
|
|
444
|
+
|
|
445
|
+
- Does not add or modify form validation — that is `@validate-page`'s job
|
|
446
|
+
- Does not create new pages or components
|
|
447
|
+
- Does not modify App.jsx routing
|
|
448
|
+
- Does not touch backend files (NodeJS service)
|
|
449
|
+
- Does not add authentication/session management beyond what apiHandler
|
|
450
|
+
already provides
|
|
451
|
+
- Does not add global state (Redux, Context API)
|
|
452
|
+
- Does not handle file uploads (beyond wiring the existing input to
|
|
453
|
+
an API call with FormData if the input type is "file")
|