codeninja 3.2.0 → 4.0.1
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 +15 -4
- 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
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
---
|
|
2
|
+
applyTo: "**/*.jsx,**/src/**"
|
|
3
|
+
---
|
|
4
|
+
|
|
5
|
+
# codeninja — ReactJS Architecture Standards
|
|
6
|
+
|
|
7
|
+
## apiClient.js — 4 Responsibilities
|
|
8
|
+
1. Static headers: `api-key`, `Accept-Language`, `Content-Type: text/plain`
|
|
9
|
+
2. Request interceptor: AES-encrypt body + attach encrypted token from localStorage
|
|
10
|
+
3. Response interceptor (success): decrypt + parse JSON; responsecode -1 → logout
|
|
11
|
+
4. Response interceptor (error): ERR_NETWORK/401 → logout + error message
|
|
12
|
+
|
|
13
|
+
## apiHandler.js Standard
|
|
14
|
+
- One exported async function per backend endpoint
|
|
15
|
+
- No try/catch, no decryption (interceptors handle it)
|
|
16
|
+
- All API paths here — never in page components
|
|
17
|
+
|
|
18
|
+
## Backend Linking Rule
|
|
19
|
+
ReactJS CANNOT be initialized without a linked NodeJS backend.
|
|
20
|
+
Inherits from linked service: `encryption_key`, `encryption_iv`, `api_key`, `port`.
|
|
21
|
+
NEVER ask user for these — always read from `context.services[linked_service]`.
|
|
22
|
+
|
|
23
|
+
## Vanilla CSS Only
|
|
24
|
+
- Per-page: `<PageName>.module.css`
|
|
25
|
+
- Global: `public/assets/css/style.css`
|
|
26
|
+
- No Tailwind, no CSS-in-JS
|
|
27
|
+
|
|
28
|
+
## .env Standard
|
|
29
|
+
```
|
|
30
|
+
REACT_APP_BASE_URL=http://localhost:<linked_port>/api/v1/
|
|
31
|
+
REACT_APP_API_KEY=<inherited>
|
|
32
|
+
REACT_APP_KEY=<inherited>
|
|
33
|
+
REACT_APP_IV=<inherited>
|
|
34
|
+
```
|
|
35
|
+
|
|
36
|
+
## Wave Generation Order
|
|
37
|
+
Before generating any file, read `.codeninja/tasks/generate-react-*.task.md`.
|
|
38
|
+
|
|
39
|
+
Wave 1: package.json, .env, .gitignore, README.md, public/index.html, public/assets/css/style.css, .htaccess (root + public)
|
|
40
|
+
Wave 2: src/api/apiClient.js, src/api/apiHandler.js
|
|
41
|
+
Wave 3: src/pages/Welcome/index.jsx, src/pages/Welcome/Welcome.module.css, src/App.jsx, src/index.jsx
|
|
42
|
+
Wave 4: Dockerfile, nginx.conf, .dockerignore
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "codeninja",
|
|
3
|
-
"version": "
|
|
4
|
-
"description": "AI agent scaffolding system — NodeJS, ReactJS, and database projects. IDE-aware:
|
|
3
|
+
"version": "4.0.1",
|
|
4
|
+
"description": "AI agent scaffolding system — NodeJS (JS/TS), ReactJS, and database projects. Multi-agent architecture with true parallel sub-agents. Supports Prisma ORM, TypeScript, and bcrypt/argon2 password hashing. IDE-aware: Claude Code, Antigravity, Cursor, VS Code.",
|
|
5
5
|
"private": false,
|
|
6
6
|
"bin": {
|
|
7
7
|
"codeninja": "cli.js"
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
---
|
|
2
|
+
type: task
|
|
3
|
+
name: ask-hashing-library
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
Condition: only run if `context.current_init.init_mode == "manual"` AND
|
|
7
|
+
`context.current_init.project_type == "nodejs"`.
|
|
8
|
+
In fast mode, `generate-fast-defaults` sets `hashing_library = "bcryptjs"`
|
|
9
|
+
automatically — skip this task.
|
|
10
|
+
|
|
11
|
+
Ask the user exactly this question:
|
|
12
|
+
|
|
13
|
+
"Which password hashing library should this service use?"
|
|
14
|
+
|
|
15
|
+
Present options:
|
|
16
|
+
1. bcryptjs — pure JavaScript, no native bindings, easier to install (recommended)
|
|
17
|
+
2. argon2 — stronger algorithm, requires native build tools
|
|
18
|
+
|
|
19
|
+
Wait for user selection.
|
|
20
|
+
|
|
21
|
+
Store result in: `context.current_init.hashing_library`
|
|
22
|
+
- Option 1 → "bcryptjs"
|
|
23
|
+
- Option 2 → "argon2"
|
|
24
|
+
|
|
25
|
+
Show confirmation based on selection:
|
|
26
|
+
- bcryptjs → "bcryptjs will be added to package.json. Passwords will be hashed
|
|
27
|
+
with bcrypt (SALT_ROUNDS = 12)."
|
|
28
|
+
- argon2 → "argon2 will be added to package.json. Passwords will be hashed
|
|
29
|
+
with argon2id. Native build tools (node-gyp) must be available."
|
|
30
|
+
|
|
31
|
+
Do not ask any other question in this task.
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
---
|
|
2
|
+
type: task
|
|
3
|
+
name: ask-language-type
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# Task: ask-language-type
|
|
7
|
+
|
|
8
|
+
Condition: only run if `context.current_init.project_type == "nodejs"`.
|
|
9
|
+
Skip entirely for reactjs and database-only projects.
|
|
10
|
+
|
|
11
|
+
If `context.current_init.init_mode == "fast"` → skip this task,
|
|
12
|
+
set `context.current_init.language = "javascript"` silently, return.
|
|
13
|
+
|
|
14
|
+
Ask: "What language would you like to use for this service?"
|
|
15
|
+
|
|
16
|
+
Options:
|
|
17
|
+
1. JavaScript (default) — CommonJS require/module.exports, .js files, no build step
|
|
18
|
+
2. TypeScript — import/export, type annotations, .ts files, compiled to dist/
|
|
19
|
+
|
|
20
|
+
Guidance:
|
|
21
|
+
- JavaScript: simpler setup, runs directly with node, faster to start
|
|
22
|
+
- TypeScript: type safety, better IDE autocomplete, recommended for larger teams
|
|
23
|
+
|
|
24
|
+
Stores: `context.current_init.language` ("javascript" | "typescript")
|
|
25
|
+
|
|
26
|
+
Do not ask any other question in this task.
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
---
|
|
2
|
+
type: task
|
|
3
|
+
name: ask-new-module-name
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# Task: ask-new-module-name
|
|
7
|
+
|
|
8
|
+
Ask: "Enter the new name for '[context.current_refactor.old_module_name]':"
|
|
9
|
+
- Validate: must not already exist in the service — error if conflict
|
|
10
|
+
- Use PascalCase (e.g., "UserOrders" not "userorders")
|
|
11
|
+
- Stores: `context.current_refactor.new_module_name`
|
|
12
|
+
|
|
13
|
+
Do not ask any other question in this task.
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
---
|
|
2
|
+
type: task
|
|
3
|
+
name: ask-new-service-name
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# Task: ask-new-service-name
|
|
7
|
+
|
|
8
|
+
Ask: "Enter the new name for '[context.current_refactor.old_service_name]':"
|
|
9
|
+
- Validate: must not already exist in `context.services` — error if conflict
|
|
10
|
+
- Validate: lowercase, no spaces (suggest replacing spaces with hyphens)
|
|
11
|
+
- Stores: `context.current_refactor.new_service_name`
|
|
12
|
+
|
|
13
|
+
Do not ask any other question in this task.
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
---
|
|
2
|
+
type: task
|
|
3
|
+
name: ask-old-module-name
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# Task: ask-old-module-name
|
|
7
|
+
|
|
8
|
+
Read the target service name from: `context.current_refactor.old_service_name` (set by ask-old-service-name).
|
|
9
|
+
|
|
10
|
+
Ask: "Enter the current module name to rename:"
|
|
11
|
+
- Show available modules from `context.services[<service>].modules`
|
|
12
|
+
- Validate: must exist in the service — error if not found
|
|
13
|
+
- Stores: `context.current_refactor.old_module_name`
|
|
14
|
+
|
|
15
|
+
Do not ask any other question in this task.
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
---
|
|
2
|
+
type: task
|
|
3
|
+
name: ask-old-service-name
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# Task: ask-old-service-name
|
|
7
|
+
|
|
8
|
+
Ask: "Enter the current service name to rename:"
|
|
9
|
+
- Show available service names from `context.services` as options
|
|
10
|
+
- Validate: name must exist in `context.services` — error if not found
|
|
11
|
+
- Stores: `context.current_refactor.old_service_name`
|
|
12
|
+
|
|
13
|
+
Do not ask any other question in this task.
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
---
|
|
2
|
+
type: task
|
|
3
|
+
name: ask-orm-type
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# Task: ask-orm-type
|
|
7
|
+
|
|
8
|
+
Condition: if `context.current_init.init_mode == "fast"` → skip this task,
|
|
9
|
+
set `context.db.orm = "none"` silently, return.
|
|
10
|
+
|
|
11
|
+
Ask: "How would you like to interact with the database?"
|
|
12
|
+
|
|
13
|
+
Options:
|
|
14
|
+
1. Raw driver (default) — direct SQL with pg / mysql2 / mongoose; generates config/database.js
|
|
15
|
+
2. Prisma ORM — schema-first ORM; generates prisma/schema.prisma + config/prisma.js
|
|
16
|
+
|
|
17
|
+
Guidance to show the user:
|
|
18
|
+
- Raw driver: full SQL control, better for complex queries and existing DBA workflows
|
|
19
|
+
- Prisma: type-safe queries, auto-generated client, faster development (pairs well with TypeScript)
|
|
20
|
+
|
|
21
|
+
If `context.db.orm` is already set from a previous service init, ask:
|
|
22
|
+
"Existing services use [current value]. Keep the same? (yes / change)"
|
|
23
|
+
|
|
24
|
+
Stores: `context.db.orm` ("none" | "prisma")
|
|
25
|
+
|
|
26
|
+
Do not ask any other question in this task.
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
---
|
|
2
|
+
type: task
|
|
3
|
+
name: collect-seed-data
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# Task: collect-seed-data
|
|
7
|
+
|
|
8
|
+
Orchestrates seed row collection for `context.current_db.table_name`.
|
|
9
|
+
|
|
10
|
+
Step 1 — Run task: `ask-seed-rows-count`
|
|
11
|
+
- Stores: `context.current_db.seed_count`
|
|
12
|
+
|
|
13
|
+
Step 2 — Repeat `context.current_db.seed_count` times:
|
|
14
|
+
Run task: `ask-seed-row-values`
|
|
15
|
+
- Appends each completed row to: `context.current_db.seed_rows[]`
|
|
16
|
+
|
|
17
|
+
After all rows are collected, show preview:
|
|
18
|
+
"Seed data collected: [N] rows for [table_name]"
|
|
19
|
+
Return to calling workflow.
|
|
@@ -14,6 +14,48 @@ starts.
|
|
|
14
14
|
|
|
15
15
|
---
|
|
16
16
|
|
|
17
|
+
## Language Branch
|
|
18
|
+
|
|
19
|
+
Read `context.current_init.language` (or `context.services[name].language`).
|
|
20
|
+
|
|
21
|
+
**TypeScript — generate `app.ts` + `server.ts`:**
|
|
22
|
+
|
|
23
|
+
`app.ts`:
|
|
24
|
+
```typescript
|
|
25
|
+
import express, { Application } from 'express';
|
|
26
|
+
import cors from 'cors';
|
|
27
|
+
import helmet from 'helmet';
|
|
28
|
+
import dotenv from 'dotenv';
|
|
29
|
+
|
|
30
|
+
dotenv.config();
|
|
31
|
+
|
|
32
|
+
const app: Application = express();
|
|
33
|
+
|
|
34
|
+
app.use(cors({ origin: process.env.ALLOWED_ORIGINS?.split(',') }));
|
|
35
|
+
app.use(helmet());
|
|
36
|
+
app.use(express.json());
|
|
37
|
+
app.use(express.urlencoded({ extended: true }));
|
|
38
|
+
|
|
39
|
+
export default app;
|
|
40
|
+
```
|
|
41
|
+
|
|
42
|
+
`server.ts` (entry point):
|
|
43
|
+
```typescript
|
|
44
|
+
import app from './app';
|
|
45
|
+
import { router as v1Router } from './modules/v1/route_manager';
|
|
46
|
+
|
|
47
|
+
app.use('/api/v1', v1Router);
|
|
48
|
+
|
|
49
|
+
const PORT = parseInt(process.env.PORT || '3000', 10);
|
|
50
|
+
app.listen(PORT, () => {
|
|
51
|
+
console.log(`[${process.env.PROJECT_NAME}] running on port ${PORT}`);
|
|
52
|
+
});
|
|
53
|
+
```
|
|
54
|
+
|
|
55
|
+
**JavaScript — generate `app.js` (existing behavior — see below)**
|
|
56
|
+
|
|
57
|
+
---
|
|
58
|
+
|
|
17
59
|
## Dependencies to Import
|
|
18
60
|
|
|
19
61
|
- `dotenv` — called as `require('dotenv').config()` on the very first
|
|
@@ -15,6 +15,19 @@ config/database.js. The object is named `common` and exported directly.
|
|
|
15
15
|
|
|
16
16
|
---
|
|
17
17
|
|
|
18
|
+
## Language Branch
|
|
19
|
+
|
|
20
|
+
Read `context.current_init.language` (or `context.services[name].language`).
|
|
21
|
+
|
|
22
|
+
**TypeScript — generate `config/common.ts`:**
|
|
23
|
+
Same content as JS variant but with typed exports.
|
|
24
|
+
Use `export const GLOBALS = Object.freeze({ ... } as const);`
|
|
25
|
+
All function signatures typed.
|
|
26
|
+
|
|
27
|
+
**JavaScript — generate `config/common.js` (existing behavior — see below)**
|
|
28
|
+
|
|
29
|
+
---
|
|
30
|
+
|
|
18
31
|
## Dependencies to Import
|
|
19
32
|
|
|
20
33
|
- `./database` — imported as `con`. Used by all database functions.
|
|
@@ -15,6 +15,19 @@ using Object.freeze so no file can accidentally mutate it at runtime.
|
|
|
15
15
|
|
|
16
16
|
---
|
|
17
17
|
|
|
18
|
+
## Language Branch
|
|
19
|
+
|
|
20
|
+
Read `context.current_init.language` (or `context.services[name].language`).
|
|
21
|
+
|
|
22
|
+
**TypeScript — generate `config/constants.ts`:**
|
|
23
|
+
Same content as JS variant.
|
|
24
|
+
Use `export const` for all exported values.
|
|
25
|
+
Add type annotations where helpful: `export const PORT: number = parseInt(process.env.PORT || '3000', 10);`
|
|
26
|
+
|
|
27
|
+
**JavaScript — generate `config/constants.js` (existing behavior — see below)**
|
|
28
|
+
|
|
29
|
+
---
|
|
30
|
+
|
|
18
31
|
## Dependencies
|
|
19
32
|
|
|
20
33
|
No imports from within the service. Only reads from process.env which
|
|
@@ -15,6 +15,38 @@ the correct implementation.
|
|
|
15
15
|
|
|
16
16
|
---
|
|
17
17
|
|
|
18
|
+
## ORM Branch
|
|
19
|
+
|
|
20
|
+
Read `context.db.orm` before generating anything.
|
|
21
|
+
|
|
22
|
+
**If `orm == "prisma"`:**
|
|
23
|
+
- Do NOT generate `config/database.js` or `config/database.ts`
|
|
24
|
+
- Instead: run task `generate-prisma-schema` then run task `generate-prisma-client`
|
|
25
|
+
- Update `.env` to use `DATABASE_URL` instead of individual DB_HOST/PORT/NAME/USER/PASS:
|
|
26
|
+
- PostgreSQL: `DATABASE_URL="postgresql://<user>:<password>@<host>:<port>/<db_name>?schema=public"`
|
|
27
|
+
- MySQL: `DATABASE_URL="mysql://<user>:<password>@<host>:<port>/<db_name>"`
|
|
28
|
+
- MongoDB: `DATABASE_URL="mongodb+srv://<user>:<password>@<cluster>/<db_name>?retryWrites=true&w=majority"`
|
|
29
|
+
- Skip the rest of this task after running those two tasks.
|
|
30
|
+
|
|
31
|
+
**If `orm == "none"`:**
|
|
32
|
+
- Continue with raw driver generation below (existing behavior).
|
|
33
|
+
|
|
34
|
+
---
|
|
35
|
+
|
|
36
|
+
## Language Branch (raw driver path only — Prisma path already handles JS/TS in generate-prisma-client)
|
|
37
|
+
|
|
38
|
+
Read `context.current_init.language` (or `context.services[name].language`).
|
|
39
|
+
|
|
40
|
+
**TypeScript — generate `config/database.ts`:**
|
|
41
|
+
Same pool/connection setup as JS but with typed imports.
|
|
42
|
+
PostgreSQL: `import { Pool, PoolConfig } from 'pg';`
|
|
43
|
+
MySQL: `import mysql from 'mysql2/promise';`
|
|
44
|
+
MongoDB: `import mongoose from 'mongoose';`
|
|
45
|
+
|
|
46
|
+
**JavaScript — generate `config/database.js` (existing behavior — see below)**
|
|
47
|
+
|
|
48
|
+
---
|
|
49
|
+
|
|
18
50
|
## Dependencies to Import
|
|
19
51
|
|
|
20
52
|
- `../logger/logging` — imported as `log`. Used for connection error
|
|
@@ -6,6 +6,34 @@ agent: nodejs-agent
|
|
|
6
6
|
|
|
7
7
|
# File: utilities/encryption.js
|
|
8
8
|
|
|
9
|
+
## SCOPE: Transport Encryption Only
|
|
10
|
+
|
|
11
|
+
`utilities/encryption.js` (or `.ts`) handles AES-256-CBC **transport encryption only**:
|
|
12
|
+
- Encrypting outgoing API response payloads
|
|
13
|
+
- Decrypting incoming encrypted request payloads
|
|
14
|
+
- Encrypting/decrypting session tokens for transmission
|
|
15
|
+
|
|
16
|
+
**This file does NOT handle passwords.** Password hashing is handled exclusively by
|
|
17
|
+
`utilities/hashing.js` (see task: generate-hashing). Never import encryption functions
|
|
18
|
+
for password storage. Never store an AES-encrypted password — passwords must be
|
|
19
|
+
bcrypt/argon2 hashed (one-way, irreversible).
|
|
20
|
+
|
|
21
|
+
---
|
|
22
|
+
|
|
23
|
+
## Language Branch
|
|
24
|
+
|
|
25
|
+
Read `context.current_init.language` (or `context.services[name].language`).
|
|
26
|
+
|
|
27
|
+
**TypeScript — generate `utilities/encryption.ts`:**
|
|
28
|
+
Same AES-256-CBC encrypt/decrypt functions as JS variant.
|
|
29
|
+
Use `import CryptoJS from 'crypto-js';` (or `import cryptlib from 'cryptlib';` for app client type).
|
|
30
|
+
All function signatures typed: `export function encrypt(data: unknown): string`
|
|
31
|
+
and `export function decrypt(ciphertext: string): unknown`.
|
|
32
|
+
|
|
33
|
+
**JavaScript — generate `utilities/encryption.js` (existing behavior — see below)**
|
|
34
|
+
|
|
35
|
+
---
|
|
36
|
+
|
|
9
37
|
## Purpose
|
|
10
38
|
Single source of truth for all encryption and decryption operations in the
|
|
11
39
|
service. All other files that need to encrypt or decrypt call this module.
|
|
@@ -50,6 +50,13 @@ Validate after generation:
|
|
|
50
50
|
- encryption_iv must equal the first 16 characters of encryption_key —
|
|
51
51
|
re-derive if not
|
|
52
52
|
|
|
53
|
+
### Language and Hashing Library
|
|
54
|
+
- `language` → "javascript" (TypeScript requires manual selection — never auto-picked in fast mode)
|
|
55
|
+
- `hashing_library` → "bcryptjs" (fast mode default — pure JS, no native build tools required)
|
|
56
|
+
|
|
57
|
+
### ORM Default (nodejs only, if not already set)
|
|
58
|
+
- `context.db.orm` → "none" if not already set (raw driver — Prisma requires manual selection)
|
|
59
|
+
|
|
53
60
|
### Redis Config (nodejs only — skip for reactjs)
|
|
54
61
|
- `context.current_init.redis_host` → `"localhost"`
|
|
55
62
|
- `context.current_init.redis_port` → `6379`
|
|
@@ -0,0 +1,180 @@
|
|
|
1
|
+
---
|
|
2
|
+
type: task
|
|
3
|
+
name: generate-hashing
|
|
4
|
+
agent: nodejs-agent
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
# File: utilities/hashing.js OR utilities/hashing.ts
|
|
8
|
+
|
|
9
|
+
## Purpose
|
|
10
|
+
Single source of truth for all password hashing and verification in the service.
|
|
11
|
+
All code that needs to hash or verify a password calls this module.
|
|
12
|
+
No other file in the service imports bcryptjs or argon2 directly.
|
|
13
|
+
This file handles one-way password storage ONLY.
|
|
14
|
+
|
|
15
|
+
## SCOPE BOUNDARY
|
|
16
|
+
|
|
17
|
+
NEVER use `encryption.js` / `decrypt` / AES / KEY / IV in this file.
|
|
18
|
+
This is not transport encryption — it is irreversible password hashing.
|
|
19
|
+
Do not import or reference `../utilities/encryption` from this file.
|
|
20
|
+
|
|
21
|
+
---
|
|
22
|
+
|
|
23
|
+
## Active library and language
|
|
24
|
+
|
|
25
|
+
Read `context.current_init.hashing_library` (or
|
|
26
|
+
`context.services[<name>].hashing_library`) — value is `"bcryptjs"` or
|
|
27
|
+
`"argon2"`.
|
|
28
|
+
|
|
29
|
+
Read `context.current_init.language` (or `context.services[<name>].language`)
|
|
30
|
+
— value is `"javascript"` or `"typescript"`.
|
|
31
|
+
|
|
32
|
+
Generate the matching variant below. Do not emit unused variants.
|
|
33
|
+
|
|
34
|
+
---
|
|
35
|
+
|
|
36
|
+
## JavaScript — bcryptjs variant
|
|
37
|
+
|
|
38
|
+
```javascript
|
|
39
|
+
const bcrypt = require('bcryptjs');
|
|
40
|
+
|
|
41
|
+
const SALT_ROUNDS = 12;
|
|
42
|
+
|
|
43
|
+
/**
|
|
44
|
+
* Hashes a plaintext password using bcrypt.
|
|
45
|
+
*
|
|
46
|
+
* @param {string} plaintext - The raw password string to hash.
|
|
47
|
+
* @returns {Promise<string>} The bcrypt hash string.
|
|
48
|
+
*/
|
|
49
|
+
async function hashPassword(plaintext) {
|
|
50
|
+
return bcrypt.hash(plaintext, SALT_ROUNDS);
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
/**
|
|
54
|
+
* Verifies a plaintext password against a stored bcrypt hash.
|
|
55
|
+
*
|
|
56
|
+
* @param {string} plaintext - The raw password to verify.
|
|
57
|
+
* @param {string} hash - The stored bcrypt hash.
|
|
58
|
+
* @returns {Promise<boolean>} True if the password matches the hash.
|
|
59
|
+
*/
|
|
60
|
+
async function verifyPassword(plaintext, hash) {
|
|
61
|
+
return bcrypt.compare(plaintext, hash);
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
module.exports = { hashPassword, verifyPassword };
|
|
65
|
+
```
|
|
66
|
+
|
|
67
|
+
---
|
|
68
|
+
|
|
69
|
+
## JavaScript — argon2 variant
|
|
70
|
+
|
|
71
|
+
```javascript
|
|
72
|
+
const argon2 = require('argon2');
|
|
73
|
+
|
|
74
|
+
/**
|
|
75
|
+
* Hashes a plaintext password using argon2id.
|
|
76
|
+
*
|
|
77
|
+
* @param {string} plaintext - The raw password string to hash.
|
|
78
|
+
* @returns {Promise<string>} The argon2 hash string.
|
|
79
|
+
*/
|
|
80
|
+
async function hashPassword(plaintext) {
|
|
81
|
+
return argon2.hash(plaintext, { type: argon2.argon2id });
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
/**
|
|
85
|
+
* Verifies a plaintext password against a stored argon2 hash.
|
|
86
|
+
*
|
|
87
|
+
* @param {string} plaintext - The raw password to verify.
|
|
88
|
+
* @param {string} hash - The stored argon2 hash.
|
|
89
|
+
* @returns {Promise<boolean>} True if the password matches the hash.
|
|
90
|
+
*/
|
|
91
|
+
async function verifyPassword(plaintext, hash) {
|
|
92
|
+
return argon2.verify(hash, plaintext);
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
module.exports = { hashPassword, verifyPassword };
|
|
96
|
+
```
|
|
97
|
+
|
|
98
|
+
---
|
|
99
|
+
|
|
100
|
+
## TypeScript — bcryptjs variant
|
|
101
|
+
|
|
102
|
+
```typescript
|
|
103
|
+
import bcrypt from 'bcryptjs';
|
|
104
|
+
|
|
105
|
+
const SALT_ROUNDS = 12;
|
|
106
|
+
|
|
107
|
+
/**
|
|
108
|
+
* Hashes a plaintext password using bcrypt.
|
|
109
|
+
*
|
|
110
|
+
* @param {string} plaintext - The raw password string to hash.
|
|
111
|
+
* @returns {Promise<string>} The bcrypt hash string.
|
|
112
|
+
*/
|
|
113
|
+
export async function hashPassword(plaintext: string): Promise<string> {
|
|
114
|
+
return bcrypt.hash(plaintext, SALT_ROUNDS);
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
/**
|
|
118
|
+
* Verifies a plaintext password against a stored bcrypt hash.
|
|
119
|
+
*
|
|
120
|
+
* @param {string} plaintext - The raw password to verify.
|
|
121
|
+
* @param {string} hash - The stored bcrypt hash.
|
|
122
|
+
* @returns {Promise<boolean>} True if the password matches the hash.
|
|
123
|
+
*/
|
|
124
|
+
export async function verifyPassword(plaintext: string, hash: string): Promise<boolean> {
|
|
125
|
+
return bcrypt.compare(plaintext, hash);
|
|
126
|
+
}
|
|
127
|
+
```
|
|
128
|
+
|
|
129
|
+
---
|
|
130
|
+
|
|
131
|
+
## TypeScript — argon2 variant
|
|
132
|
+
|
|
133
|
+
```typescript
|
|
134
|
+
import argon2 from 'argon2';
|
|
135
|
+
|
|
136
|
+
/**
|
|
137
|
+
* Hashes a plaintext password using argon2id.
|
|
138
|
+
*
|
|
139
|
+
* @param {string} plaintext - The raw password string to hash.
|
|
140
|
+
* @returns {Promise<string>} The argon2 hash string.
|
|
141
|
+
*/
|
|
142
|
+
export async function hashPassword(plaintext: string): Promise<string> {
|
|
143
|
+
return argon2.hash(plaintext, { type: argon2.argon2id });
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
/**
|
|
147
|
+
* Verifies a plaintext password against a stored argon2 hash.
|
|
148
|
+
*
|
|
149
|
+
* @param {string} plaintext - The raw password to verify.
|
|
150
|
+
* @param {string} hash - The stored argon2 hash.
|
|
151
|
+
* @returns {Promise<boolean>} True if the password matches the hash.
|
|
152
|
+
*/
|
|
153
|
+
export async function verifyPassword(plaintext: string, hash: string): Promise<boolean> {
|
|
154
|
+
return argon2.verify(hash, plaintext);
|
|
155
|
+
}
|
|
156
|
+
```
|
|
157
|
+
|
|
158
|
+
---
|
|
159
|
+
|
|
160
|
+
## Export
|
|
161
|
+
|
|
162
|
+
JavaScript variants export via CommonJS:
|
|
163
|
+
```
|
|
164
|
+
module.exports = { hashPassword, verifyPassword }
|
|
165
|
+
```
|
|
166
|
+
|
|
167
|
+
TypeScript variants use named ES module exports (no default export).
|
|
168
|
+
|
|
169
|
+
Every file that imports this module destructures exactly what it needs:
|
|
170
|
+
`const { hashPassword, verifyPassword } = require('../utilities/hashing')`
|
|
171
|
+
|
|
172
|
+
---
|
|
173
|
+
|
|
174
|
+
## What This File Does NOT Do
|
|
175
|
+
|
|
176
|
+
- Does not read `req` or `res` — no Express objects
|
|
177
|
+
- Does not log — callers handle logging
|
|
178
|
+
- Does not import `encryption.js` or use AES, KEY, or IV
|
|
179
|
+
- Does not provide a `decrypt` or `unhash` function — hashing is irreversible
|
|
180
|
+
- Does not conditionally skip hashing — always hashes when called
|
|
@@ -17,6 +17,19 @@ delegated to `utilities/validator.js`.
|
|
|
17
17
|
|
|
18
18
|
---
|
|
19
19
|
|
|
20
|
+
## Language Branch
|
|
21
|
+
|
|
22
|
+
Read `context.current_init.language` (or `context.services[name].language`).
|
|
23
|
+
|
|
24
|
+
**TypeScript — generate `headerValidator.ts`:**
|
|
25
|
+
All exports are typed middleware functions with signature `(req: Request, res: Response, next: NextFunction): void`.
|
|
26
|
+
Use `import { Request, Response, NextFunction } from 'express';` at the top.
|
|
27
|
+
All other logic identical to JS variant — same checks, same middleware order.
|
|
28
|
+
|
|
29
|
+
**JavaScript — generate `headerValidator.js` (existing behavior — see below)**
|
|
30
|
+
|
|
31
|
+
---
|
|
32
|
+
|
|
20
33
|
## Dependencies to Import
|
|
21
34
|
|
|
22
35
|
- `../config/constants` — GLOBALS object containing API_KEY and other
|
|
@@ -19,6 +19,26 @@ starting the service.
|
|
|
19
19
|
|
|
20
20
|
---
|
|
21
21
|
|
|
22
|
+
## Language Branch
|
|
23
|
+
|
|
24
|
+
Read `context.current_init.language` (or `context.services[name].language`).
|
|
25
|
+
|
|
26
|
+
**TypeScript — generate `utilities/ioRedis.ts`:**
|
|
27
|
+
```typescript
|
|
28
|
+
import Redis from 'ioredis';
|
|
29
|
+
|
|
30
|
+
const redisClient = new Redis({
|
|
31
|
+
host: process.env.REDIS_HOST || 'localhost',
|
|
32
|
+
port: parseInt(process.env.REDIS_PORT || '6379', 10),
|
|
33
|
+
});
|
|
34
|
+
|
|
35
|
+
export default redisClient;
|
|
36
|
+
```
|
|
37
|
+
|
|
38
|
+
**JavaScript — generate `utilities/ioRedis.js` (existing behavior — see below)**
|
|
39
|
+
|
|
40
|
+
---
|
|
41
|
+
|
|
22
42
|
## Dependencies to Import
|
|
23
43
|
|
|
24
44
|
- `ioredis` — imported as `IORedis` (capital letters). The Redis client
|
|
@@ -19,6 +19,18 @@ area. This makes it easy to find and add related messages together.
|
|
|
19
19
|
|
|
20
20
|
---
|
|
21
21
|
|
|
22
|
+
## Language Branch
|
|
23
|
+
|
|
24
|
+
Read `context.current_init.language` (or `context.services[name].language`).
|
|
25
|
+
|
|
26
|
+
**TypeScript — generate `languages/en.ts`:**
|
|
27
|
+
Same message key/value object as JS variant.
|
|
28
|
+
Use: `const messages: Record<string, string> = { ... }; export default messages;`
|
|
29
|
+
|
|
30
|
+
**JavaScript — generate `languages/en.js` (existing behavior — see below)**
|
|
31
|
+
|
|
32
|
+
---
|
|
33
|
+
|
|
22
34
|
## Structure and Sections
|
|
23
35
|
|
|
24
36
|
### Section 1 — Validator Messages
|
|
@@ -16,6 +16,18 @@ than 10 days.
|
|
|
16
16
|
|
|
17
17
|
---
|
|
18
18
|
|
|
19
|
+
## Language Branch
|
|
20
|
+
|
|
21
|
+
Read `context.current_init.language` (or `context.services[name].language`).
|
|
22
|
+
|
|
23
|
+
**TypeScript — generate `logger/logging.ts`:**
|
|
24
|
+
Same custom file-based logger as JS variant with typed function signatures.
|
|
25
|
+
`export function log(message: string, level?: 'info' | 'error' | 'warn'): void`
|
|
26
|
+
|
|
27
|
+
**JavaScript — generate `logger/logging.js` (existing behavior — see below)**
|
|
28
|
+
|
|
29
|
+
---
|
|
30
|
+
|
|
19
31
|
## Dependencies to Import
|
|
20
32
|
|
|
21
33
|
- `fs` — Node.js built-in. Used for file existence checks, directory
|