@valentia-ai-skills/framework 1.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 +103 -0
- package/bin/cli.js +482 -0
- package/package.json +42 -0
- package/scripts/postinstall.js +18 -0
- package/skills/global/api-design/SKILL.md +248 -0
- package/skills/global/api-design/tests/test-prompts.md +25 -0
- package/skills/global/code-standards/SKILL.md +245 -0
- package/skills/global/code-standards/tests/test-prompts.md +26 -0
- package/skills/global/deployment/SKILL.md +240 -0
- package/skills/global/deployment/tests/test-prompts.md +27 -0
- package/skills/global/documentation/SKILL.md +298 -0
- package/skills/global/documentation/tests/test-prompts.md +26 -0
- package/skills/global/git-workflow/SKILL.md +177 -0
- package/skills/global/git-workflow/tests/test-prompts.md +11 -0
- package/skills/global/security-baseline/SKILL.md +239 -0
- package/skills/global/security-baseline/tests/test-prompts.md +23 -0
- package/skills/global/testing-standards/SKILL.md +257 -0
- package/skills/global/testing-standards/tests/test-prompts.md +25 -0
- package/skills/onboarding/SKILL.md +110 -0
- package/skills/stack/devops/SKILL.md +220 -0
- package/skills/stack/devops/tests/test-prompts.md +29 -0
- package/skills/stack/node-backend/SKILL.md +304 -0
- package/skills/stack/node-backend/tests/test-prompts.md +27 -0
- package/skills/stack/python-backend/SKILL.md +304 -0
- package/skills/stack/python-backend/tests/test-prompts.md +27 -0
- package/skills/stack/react/SKILL.md +251 -0
- package/skills/stack/react/tests/test-prompts.md +26 -0
- package/skills/stack/react-native/SKILL.md +255 -0
- package/skills/stack/react-native/tests/test-prompts.md +26 -0
|
@@ -0,0 +1,177 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: git-workflow
|
|
3
|
+
description: >
|
|
4
|
+
Organization-wide Git workflow standards. Use this skill whenever the developer
|
|
5
|
+
is working with Git — creating branches, writing commit messages, preparing PRs,
|
|
6
|
+
merging code, resolving conflicts, or discussing branching strategy. Also triggers
|
|
7
|
+
when asked to "commit", "push", "merge", "create a PR", "branch off", "tag a
|
|
8
|
+
release", "cherry-pick", "rebase", or any other Git operation. Applies to all
|
|
9
|
+
teams and all repositories in the organization.
|
|
10
|
+
version: "1.0.0"
|
|
11
|
+
scope: global
|
|
12
|
+
author: Framework Admin
|
|
13
|
+
last_reviewed: 2026-03-19
|
|
14
|
+
---
|
|
15
|
+
|
|
16
|
+
# Git Workflow
|
|
17
|
+
|
|
18
|
+
## Overview
|
|
19
|
+
|
|
20
|
+
Standardized Git workflow that all teams follow. Ensures clean history, traceable
|
|
21
|
+
changes, and smooth code review processes across 10+ teams working on different
|
|
22
|
+
projects.
|
|
23
|
+
|
|
24
|
+
## 1. Branching Strategy
|
|
25
|
+
|
|
26
|
+
We use a **trunk-based development** model with short-lived feature branches.
|
|
27
|
+
|
|
28
|
+
### Branch Naming Convention
|
|
29
|
+
|
|
30
|
+
```
|
|
31
|
+
{type}/{ticket-id}/{short-description}
|
|
32
|
+
```
|
|
33
|
+
|
|
34
|
+
| Type | Use Case | Example |
|
|
35
|
+
|------|----------|---------|
|
|
36
|
+
| `feature/` | New functionality | `feature/PROJ-123/user-registration` |
|
|
37
|
+
| `fix/` | Bug fixes | `fix/PROJ-456/login-timeout` |
|
|
38
|
+
| `hotfix/` | Production emergency | `hotfix/PROJ-789/payment-crash` |
|
|
39
|
+
| `chore/` | Maintenance, deps, config | `chore/PROJ-101/upgrade-node-20` |
|
|
40
|
+
| `refactor/` | Code improvements | `refactor/PROJ-202/extract-auth-service` |
|
|
41
|
+
| `docs/` | Documentation only | `docs/PROJ-303/api-endpoint-guide` |
|
|
42
|
+
|
|
43
|
+
### Rules
|
|
44
|
+
- Branch from `main` (or `develop` if your team uses GitFlow)
|
|
45
|
+
- Branch lifetime: **maximum 3 days** — if longer, break the work into smaller PRs
|
|
46
|
+
- Delete branches after merge
|
|
47
|
+
- Never commit directly to `main`
|
|
48
|
+
|
|
49
|
+
## 2. Commit Messages
|
|
50
|
+
|
|
51
|
+
### Format
|
|
52
|
+
|
|
53
|
+
```
|
|
54
|
+
{type}({scope}): {short description}
|
|
55
|
+
|
|
56
|
+
{optional body — explain WHY, not WHAT}
|
|
57
|
+
|
|
58
|
+
{optional footer — ticket references, breaking changes}
|
|
59
|
+
```
|
|
60
|
+
|
|
61
|
+
### Types
|
|
62
|
+
|
|
63
|
+
| Type | When |
|
|
64
|
+
|------|------|
|
|
65
|
+
| `feat` | New feature |
|
|
66
|
+
| `fix` | Bug fix |
|
|
67
|
+
| `refactor` | Code change that doesn't fix a bug or add a feature |
|
|
68
|
+
| `docs` | Documentation only |
|
|
69
|
+
| `test` | Adding or updating tests |
|
|
70
|
+
| `chore` | Build, deps, CI config |
|
|
71
|
+
| `style` | Formatting, whitespace (no logic change) |
|
|
72
|
+
| `perf` | Performance improvement |
|
|
73
|
+
|
|
74
|
+
### Examples
|
|
75
|
+
|
|
76
|
+
✅ Good:
|
|
77
|
+
```
|
|
78
|
+
feat(auth): add password reset via email
|
|
79
|
+
|
|
80
|
+
Users can now request a password reset link sent to their
|
|
81
|
+
registered email. Link expires after 24 hours.
|
|
82
|
+
|
|
83
|
+
Closes PROJ-123
|
|
84
|
+
```
|
|
85
|
+
|
|
86
|
+
```
|
|
87
|
+
fix(cart): prevent duplicate items on rapid click
|
|
88
|
+
|
|
89
|
+
Added debounce to add-to-cart handler. Previously, rapid
|
|
90
|
+
clicking could add the same item multiple times before
|
|
91
|
+
the UI updated.
|
|
92
|
+
|
|
93
|
+
Fixes PROJ-456
|
|
94
|
+
```
|
|
95
|
+
|
|
96
|
+
❌ Bad:
|
|
97
|
+
```
|
|
98
|
+
fixed stuff // no type, no scope, vague
|
|
99
|
+
update // meaningless
|
|
100
|
+
WIP // don't commit WIP to shared branches
|
|
101
|
+
feat: changes // no scope, no description
|
|
102
|
+
```
|
|
103
|
+
|
|
104
|
+
### Rules
|
|
105
|
+
- Subject line: max 72 characters
|
|
106
|
+
- Use imperative mood: "add feature" not "added feature"
|
|
107
|
+
- No period at end of subject
|
|
108
|
+
- Body wraps at 80 characters
|
|
109
|
+
- Reference ticket numbers in footer
|
|
110
|
+
|
|
111
|
+
## 3. Pull Requests
|
|
112
|
+
|
|
113
|
+
### PR Title Format
|
|
114
|
+
Same as commit message format:
|
|
115
|
+
```
|
|
116
|
+
feat(auth): add password reset via email
|
|
117
|
+
```
|
|
118
|
+
|
|
119
|
+
### PR Description Template
|
|
120
|
+
Every PR must include:
|
|
121
|
+
1. **What** — One sentence describing the change
|
|
122
|
+
2. **Why** — Context for why this change is needed
|
|
123
|
+
3. **How** — Key implementation decisions
|
|
124
|
+
4. **Testing** — How you verified this works
|
|
125
|
+
5. **Screenshots** — If UI changes (before/after)
|
|
126
|
+
|
|
127
|
+
### PR Size Rules
|
|
128
|
+
- **Target**: Under 400 lines changed
|
|
129
|
+
- **Hard limit**: 800 lines — larger PRs must be split
|
|
130
|
+
- Exception: Generated files, migrations, dependency updates
|
|
131
|
+
|
|
132
|
+
### Review Requirements
|
|
133
|
+
- Minimum 1 approval required
|
|
134
|
+
- 2 approvals for: security-related changes, shared library changes, infrastructure changes
|
|
135
|
+
- All CI checks must pass
|
|
136
|
+
- No unresolved comments
|
|
137
|
+
|
|
138
|
+
### Merge Strategy
|
|
139
|
+
- **Squash merge** for feature branches (clean history)
|
|
140
|
+
- **Merge commit** for release branches (preserve history)
|
|
141
|
+
- Never force push to `main`
|
|
142
|
+
|
|
143
|
+
## 4. Release Tagging
|
|
144
|
+
|
|
145
|
+
### Version Format
|
|
146
|
+
Semantic versioning: `vMAJOR.MINOR.PATCH`
|
|
147
|
+
|
|
148
|
+
```
|
|
149
|
+
v1.0.0 — initial release
|
|
150
|
+
v1.1.0 — new feature added
|
|
151
|
+
v1.1.1 — bug fix
|
|
152
|
+
v2.0.0 — breaking change
|
|
153
|
+
```
|
|
154
|
+
|
|
155
|
+
### Tagging Process
|
|
156
|
+
```bash
|
|
157
|
+
git tag -a v1.2.0 -m "Release v1.2.0: Add user dashboard"
|
|
158
|
+
git push origin v1.2.0
|
|
159
|
+
```
|
|
160
|
+
|
|
161
|
+
## 5. Git Hygiene
|
|
162
|
+
|
|
163
|
+
- Pull and rebase before pushing: `git pull --rebase origin main`
|
|
164
|
+
- Resolve conflicts locally, never in GitHub UI
|
|
165
|
+
- Don't commit: `.env` files, `node_modules/`, build artifacts, IDE configs
|
|
166
|
+
- Keep `.gitignore` up to date
|
|
167
|
+
- Squash fixup commits before review
|
|
168
|
+
|
|
169
|
+
## Checklist
|
|
170
|
+
|
|
171
|
+
Before any Git operation, verify:
|
|
172
|
+
- [ ] Branch name follows `{type}/{ticket}/{description}` format
|
|
173
|
+
- [ ] Commit message follows conventional format with type and scope
|
|
174
|
+
- [ ] PR is under 400 lines (or justified if larger)
|
|
175
|
+
- [ ] PR description includes What/Why/How/Testing
|
|
176
|
+
- [ ] No secrets, env files, or build artifacts committed
|
|
177
|
+
- [ ] Branch is rebased on latest main
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
## Test 1: Branch Creation
|
|
2
|
+
**Prompt**: "I need to start working on a new user dashboard feature, ticket DASH-42"
|
|
3
|
+
**Expected**: Suggests `feature/DASH-42/user-dashboard` branch name, shows git checkout command
|
|
4
|
+
|
|
5
|
+
## Test 2: Commit Message Writing
|
|
6
|
+
**Prompt**: "Write a commit message for: I updated the login page to show an error when the password is wrong"
|
|
7
|
+
**Expected**: `fix(auth): show error message on incorrect password` with body explaining context
|
|
8
|
+
|
|
9
|
+
## Test 3: PR Preparation
|
|
10
|
+
**Prompt**: "Help me prepare a PR for my authentication refactor that moved from JWT to session-based auth"
|
|
11
|
+
**Expected**: PR title in conventional format, description with What/Why/How/Testing sections, notes about breaking change
|
|
@@ -0,0 +1,239 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: security-baseline
|
|
3
|
+
description: >
|
|
4
|
+
Organization-wide security standards for all code. Use this skill whenever
|
|
5
|
+
writing code that handles: authentication, authorization, passwords, tokens,
|
|
6
|
+
API keys, secrets, user input, database queries, file uploads, HTTP requests,
|
|
7
|
+
CORS, headers, cookies, sessions, encryption, hashing, or any security-sensitive
|
|
8
|
+
operation. Also triggers on: "login", "signup", "auth", "validate", "sanitize",
|
|
9
|
+
"encrypt", "hash", "permission", "role", "access control", "secret", "API key",
|
|
10
|
+
"environment variable", ".env", "OWASP", "vulnerability", "injection",
|
|
11
|
+
"XSS", "CSRF", or "security review". Applies to ALL stacks.
|
|
12
|
+
version: "1.0.0"
|
|
13
|
+
scope: global
|
|
14
|
+
author: Framework Admin
|
|
15
|
+
last_reviewed: 2026-03-19
|
|
16
|
+
---
|
|
17
|
+
|
|
18
|
+
# Security Baseline
|
|
19
|
+
|
|
20
|
+
## Overview
|
|
21
|
+
|
|
22
|
+
Non-negotiable security standards that every developer and every AI-generated
|
|
23
|
+
piece of code must follow. These rules prevent the most common vulnerability
|
|
24
|
+
classes (OWASP Top 10) and protect user data.
|
|
25
|
+
|
|
26
|
+
## 1. Secret Management
|
|
27
|
+
|
|
28
|
+
### NEVER Hardcode Secrets
|
|
29
|
+
|
|
30
|
+
Secrets must NEVER appear in code, config files, or version control.
|
|
31
|
+
|
|
32
|
+
✅ Good:
|
|
33
|
+
```typescript
|
|
34
|
+
const dbUrl = process.env.DATABASE_URL;
|
|
35
|
+
const apiKey = process.env.STRIPE_API_KEY;
|
|
36
|
+
```
|
|
37
|
+
|
|
38
|
+
❌ Bad:
|
|
39
|
+
```typescript
|
|
40
|
+
const dbUrl = "postgres://admin:password123@db.example.com/prod";
|
|
41
|
+
const apiKey = "sk_live_abc123xyz789";
|
|
42
|
+
```
|
|
43
|
+
|
|
44
|
+
### Rules
|
|
45
|
+
- All secrets go in environment variables
|
|
46
|
+
- Use `.env.example` with placeholder values (never real secrets)
|
|
47
|
+
- `.env` must be in `.gitignore` — verify this exists
|
|
48
|
+
- Use a secrets manager (Vault, AWS SSM, etc.) for production
|
|
49
|
+
- Rotate secrets on any suspected exposure
|
|
50
|
+
- Never log secrets — even partially
|
|
51
|
+
|
|
52
|
+
### Pre-Commit Check
|
|
53
|
+
If generating any config or setup code, always include:
|
|
54
|
+
```gitignore
|
|
55
|
+
# .gitignore — MUST include:
|
|
56
|
+
.env
|
|
57
|
+
.env.local
|
|
58
|
+
.env.*.local
|
|
59
|
+
*.pem
|
|
60
|
+
*.key
|
|
61
|
+
```
|
|
62
|
+
|
|
63
|
+
## 2. Input Validation
|
|
64
|
+
|
|
65
|
+
### Validate ALL User Input
|
|
66
|
+
|
|
67
|
+
Never trust input from clients, APIs, forms, URLs, or any external source.
|
|
68
|
+
|
|
69
|
+
### Rules
|
|
70
|
+
- Validate at the boundary (API endpoint / form handler)
|
|
71
|
+
- Use schema validation (Zod, Joi, class-validator, Pydantic)
|
|
72
|
+
- Validate types, lengths, formats, and ranges
|
|
73
|
+
- Reject invalid input — don't try to "fix" it
|
|
74
|
+
- Return clear error messages without exposing internals
|
|
75
|
+
|
|
76
|
+
✅ Good:
|
|
77
|
+
```typescript
|
|
78
|
+
import { z } from "zod";
|
|
79
|
+
|
|
80
|
+
const createUserSchema = z.object({
|
|
81
|
+
email: z.string().email().max(255),
|
|
82
|
+
name: z.string().min(1).max(100),
|
|
83
|
+
age: z.number().int().min(13).max(150),
|
|
84
|
+
role: z.enum(["user", "admin"]),
|
|
85
|
+
});
|
|
86
|
+
|
|
87
|
+
function createUser(req, res) {
|
|
88
|
+
const result = createUserSchema.safeParse(req.body);
|
|
89
|
+
if (!result.success) {
|
|
90
|
+
return res.status(400).json({ error: "Invalid input", details: result.error.issues });
|
|
91
|
+
}
|
|
92
|
+
// proceed with validated data: result.data
|
|
93
|
+
}
|
|
94
|
+
```
|
|
95
|
+
|
|
96
|
+
❌ Bad:
|
|
97
|
+
```typescript
|
|
98
|
+
function createUser(req, res) {
|
|
99
|
+
const { email, name, age, role } = req.body;
|
|
100
|
+
// directly using unvalidated input
|
|
101
|
+
db.users.insert({ email, name, age, role });
|
|
102
|
+
}
|
|
103
|
+
```
|
|
104
|
+
|
|
105
|
+
## 3. SQL Injection Prevention
|
|
106
|
+
|
|
107
|
+
### ALWAYS Use Parameterized Queries
|
|
108
|
+
|
|
109
|
+
Never concatenate user input into SQL strings.
|
|
110
|
+
|
|
111
|
+
✅ Good:
|
|
112
|
+
```typescript
|
|
113
|
+
// Parameterized query
|
|
114
|
+
const user = await db.query("SELECT * FROM users WHERE email = $1", [email]);
|
|
115
|
+
|
|
116
|
+
// ORM (also safe)
|
|
117
|
+
const user = await User.findOne({ where: { email } });
|
|
118
|
+
```
|
|
119
|
+
|
|
120
|
+
❌ Bad:
|
|
121
|
+
```typescript
|
|
122
|
+
// SQL INJECTION VULNERABILITY
|
|
123
|
+
const user = await db.query(`SELECT * FROM users WHERE email = '${email}'`);
|
|
124
|
+
const user = await db.query("SELECT * FROM users WHERE email = '" + email + "'");
|
|
125
|
+
```
|
|
126
|
+
|
|
127
|
+
## 4. Authentication
|
|
128
|
+
|
|
129
|
+
### Password Rules
|
|
130
|
+
- Hash with bcrypt (cost factor ≥ 12) or Argon2
|
|
131
|
+
- Never store plaintext passwords
|
|
132
|
+
- Never log passwords — even hashed
|
|
133
|
+
- Minimum 8 characters, check against breached password lists
|
|
134
|
+
|
|
135
|
+
✅ Good:
|
|
136
|
+
```typescript
|
|
137
|
+
import bcrypt from "bcrypt";
|
|
138
|
+
|
|
139
|
+
const SALT_ROUNDS = 12;
|
|
140
|
+
|
|
141
|
+
async function hashPassword(password: string): Promise<string> {
|
|
142
|
+
return bcrypt.hash(password, SALT_ROUNDS);
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
async function verifyPassword(password: string, hash: string): Promise<boolean> {
|
|
146
|
+
return bcrypt.compare(password, hash);
|
|
147
|
+
}
|
|
148
|
+
```
|
|
149
|
+
|
|
150
|
+
### Token Rules
|
|
151
|
+
- Use short-lived access tokens (15-60 minutes)
|
|
152
|
+
- Use refresh tokens for session extension
|
|
153
|
+
- Store tokens in httpOnly, secure, sameSite cookies
|
|
154
|
+
- Never store tokens in localStorage (XSS vulnerable)
|
|
155
|
+
|
|
156
|
+
✅ Good:
|
|
157
|
+
```typescript
|
|
158
|
+
res.cookie("token", jwt, {
|
|
159
|
+
httpOnly: true, // not accessible via JavaScript
|
|
160
|
+
secure: true, // HTTPS only
|
|
161
|
+
sameSite: "strict", // CSRF protection
|
|
162
|
+
maxAge: 15 * 60 * 1000, // 15 minutes
|
|
163
|
+
});
|
|
164
|
+
```
|
|
165
|
+
|
|
166
|
+
❌ Bad:
|
|
167
|
+
```typescript
|
|
168
|
+
localStorage.setItem("token", jwt); // XSS vulnerable
|
|
169
|
+
res.cookie("token", jwt); // missing security flags
|
|
170
|
+
```
|
|
171
|
+
|
|
172
|
+
## 5. Authorization
|
|
173
|
+
|
|
174
|
+
- Check permissions on EVERY protected endpoint
|
|
175
|
+
- Never rely on client-side checks alone
|
|
176
|
+
- Use role-based (RBAC) or attribute-based (ABAC) access control
|
|
177
|
+
- Verify resource ownership: user can only access THEIR data
|
|
178
|
+
|
|
179
|
+
```typescript
|
|
180
|
+
// Always verify ownership
|
|
181
|
+
async function getOrder(req, res) {
|
|
182
|
+
const order = await Order.findById(req.params.id);
|
|
183
|
+
|
|
184
|
+
if (!order) return res.status(404).json({ error: "Not found" });
|
|
185
|
+
if (order.userId !== req.user.id) return res.status(403).json({ error: "Forbidden" });
|
|
186
|
+
|
|
187
|
+
return res.json(order);
|
|
188
|
+
}
|
|
189
|
+
```
|
|
190
|
+
|
|
191
|
+
## 6. XSS Prevention
|
|
192
|
+
|
|
193
|
+
- Escape all user-generated content before rendering in HTML
|
|
194
|
+
- Use framework-provided escaping (React auto-escapes, etc.)
|
|
195
|
+
- Never use `dangerouslySetInnerHTML` (React) or `v-html` (Vue) with user content
|
|
196
|
+
- Set `Content-Security-Policy` headers
|
|
197
|
+
|
|
198
|
+
## 7. Dependency Security
|
|
199
|
+
|
|
200
|
+
- Run `npm audit` / `pip audit` in CI pipeline
|
|
201
|
+
- No known critical/high vulnerabilities in production
|
|
202
|
+
- Pin dependency versions (use lockfiles)
|
|
203
|
+
- Review dependencies before adding — prefer well-maintained packages
|
|
204
|
+
|
|
205
|
+
## 8. Logging & Error Handling
|
|
206
|
+
|
|
207
|
+
- Never log: passwords, tokens, API keys, credit cards, SSNs, PII
|
|
208
|
+
- Log: failed auth attempts, permission denials, validation failures
|
|
209
|
+
- Don't expose stack traces to users in production
|
|
210
|
+
- Return generic error messages to clients
|
|
211
|
+
|
|
212
|
+
✅ Good:
|
|
213
|
+
```typescript
|
|
214
|
+
// Log for debugging (server-side only)
|
|
215
|
+
logger.error("Payment failed", { userId: user.id, orderId: order.id, error: err.code });
|
|
216
|
+
|
|
217
|
+
// Return to client (generic)
|
|
218
|
+
res.status(500).json({ error: "Payment processing failed. Please try again." });
|
|
219
|
+
```
|
|
220
|
+
|
|
221
|
+
❌ Bad:
|
|
222
|
+
```typescript
|
|
223
|
+
// Exposes internals to client
|
|
224
|
+
res.status(500).json({ error: err.stack, query: sql, dbPassword: config.db.password });
|
|
225
|
+
```
|
|
226
|
+
|
|
227
|
+
## Checklist
|
|
228
|
+
|
|
229
|
+
Before finalizing any code that touches security:
|
|
230
|
+
- [ ] No hardcoded secrets — all from environment variables
|
|
231
|
+
- [ ] .env is in .gitignore
|
|
232
|
+
- [ ] All user input is validated with schema validation
|
|
233
|
+
- [ ] SQL queries are parameterized
|
|
234
|
+
- [ ] Passwords are hashed (bcrypt/Argon2, cost ≥ 12)
|
|
235
|
+
- [ ] Tokens are in httpOnly secure cookies (not localStorage)
|
|
236
|
+
- [ ] Authorization checks on every protected endpoint
|
|
237
|
+
- [ ] No user content rendered via dangerouslySetInnerHTML or equivalent
|
|
238
|
+
- [ ] Error messages don't expose internals
|
|
239
|
+
- [ ] No PII in logs
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
## Test 1: Login Endpoint
|
|
2
|
+
**Prompt**: "Write a login endpoint that takes email and password, checks the database, and returns a session token"
|
|
3
|
+
**Expected**:
|
|
4
|
+
- Input validation with schema (Zod/Joi)
|
|
5
|
+
- bcrypt password comparison (not plaintext)
|
|
6
|
+
- Token in httpOnly secure cookie (not localStorage)
|
|
7
|
+
- Generic error message ("Invalid credentials" not "Password wrong" vs "User not found")
|
|
8
|
+
- Rate limiting mentioned or implemented
|
|
9
|
+
|
|
10
|
+
## Test 2: Database Query with User Input
|
|
11
|
+
**Prompt**: "Write a search endpoint that finds products by name from a query parameter"
|
|
12
|
+
**Expected**:
|
|
13
|
+
- Parameterized query (not string concatenation)
|
|
14
|
+
- Input validation on query param (length, format)
|
|
15
|
+
- No SQL injection vectors
|
|
16
|
+
|
|
17
|
+
## Test 3: Configuration Setup
|
|
18
|
+
**Prompt**: "Set up the database connection and Stripe API configuration for our app"
|
|
19
|
+
**Expected**:
|
|
20
|
+
- All credentials from process.env
|
|
21
|
+
- .env.example file with placeholders
|
|
22
|
+
- .gitignore includes .env
|
|
23
|
+
- No real secrets in any code
|
|
@@ -0,0 +1,257 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: testing-standards
|
|
3
|
+
description: >
|
|
4
|
+
Organization-wide testing standards and patterns. Use this skill whenever
|
|
5
|
+
writing, reviewing, or discussing tests — unit tests, integration tests,
|
|
6
|
+
e2e tests, test coverage, mocking, stubbing, fixtures, test utilities,
|
|
7
|
+
or QA processes. Triggers on: "test", "spec", "coverage", "mock", "stub",
|
|
8
|
+
"fixture", "assertion", "expect", "describe", "it", "jest", "vitest",
|
|
9
|
+
"pytest", "cypress", "playwright", "testing-library", "TDD", "BDD",
|
|
10
|
+
"unit test", "integration test", "e2e", "end-to-end", "test plan",
|
|
11
|
+
"regression", "smoke test", "QA". Applies to all stacks.
|
|
12
|
+
version: "1.0.0"
|
|
13
|
+
scope: global
|
|
14
|
+
author: Framework Admin
|
|
15
|
+
last_reviewed: 2026-03-19
|
|
16
|
+
---
|
|
17
|
+
|
|
18
|
+
# Testing Standards
|
|
19
|
+
|
|
20
|
+
## Overview
|
|
21
|
+
|
|
22
|
+
Every team must write tests. These standards define what to test, how to test,
|
|
23
|
+
and what quality bar to maintain. The goal is confidence in deployments —
|
|
24
|
+
not 100% coverage for its own sake.
|
|
25
|
+
|
|
26
|
+
## 1. Coverage Targets
|
|
27
|
+
|
|
28
|
+
| Test Type | Minimum Coverage | Target Coverage |
|
|
29
|
+
|-----------|-----------------|-----------------|
|
|
30
|
+
| Unit Tests | 70% | 85% |
|
|
31
|
+
| Integration Tests | Key flows covered | All critical paths |
|
|
32
|
+
| E2E Tests | Happy paths | Happy + top 5 error paths |
|
|
33
|
+
|
|
34
|
+
### What Counts as "Covered"
|
|
35
|
+
- Lines of code executed during tests
|
|
36
|
+
- Branch coverage (both if/else paths)
|
|
37
|
+
- Coverage measured per-service, not org-wide
|
|
38
|
+
|
|
39
|
+
### What to Skip
|
|
40
|
+
- Generated code, type definitions, config files
|
|
41
|
+
- Third-party library wrappers (test the library's behavior, not its internals)
|
|
42
|
+
|
|
43
|
+
## 2. Test File Organization
|
|
44
|
+
|
|
45
|
+
### File Naming
|
|
46
|
+
```
|
|
47
|
+
src/
|
|
48
|
+
services/
|
|
49
|
+
user-service.ts
|
|
50
|
+
user-service.test.ts # co-located unit tests
|
|
51
|
+
|
|
52
|
+
tests/
|
|
53
|
+
integration/
|
|
54
|
+
user-registration.test.ts # integration tests
|
|
55
|
+
e2e/
|
|
56
|
+
login-flow.spec.ts # e2e tests
|
|
57
|
+
fixtures/
|
|
58
|
+
users.ts # shared test data
|
|
59
|
+
helpers/
|
|
60
|
+
test-db.ts # test utilities
|
|
61
|
+
```
|
|
62
|
+
|
|
63
|
+
### Rules
|
|
64
|
+
- Unit tests: co-located next to source file (`.test.ts`)
|
|
65
|
+
- Integration tests: in `tests/integration/`
|
|
66
|
+
- E2E tests: in `tests/e2e/` with `.spec.ts` extension
|
|
67
|
+
- Fixtures: in `tests/fixtures/`
|
|
68
|
+
- Shared helpers: in `tests/helpers/`
|
|
69
|
+
|
|
70
|
+
## 3. Test Structure — AAA Pattern
|
|
71
|
+
|
|
72
|
+
Every test follows **Arrange → Act → Assert**:
|
|
73
|
+
|
|
74
|
+
```typescript
|
|
75
|
+
describe("UserService", () => {
|
|
76
|
+
describe("createUser", () => {
|
|
77
|
+
it("should create a user with valid data", async () => {
|
|
78
|
+
// Arrange — set up test data and dependencies
|
|
79
|
+
const userData = { email: "alice@example.com", name: "Alice" };
|
|
80
|
+
const mockRepo = { save: vi.fn().mockResolvedValue({ id: "usr_123", ...userData }) };
|
|
81
|
+
const service = new UserService(mockRepo);
|
|
82
|
+
|
|
83
|
+
// Act — call the function being tested
|
|
84
|
+
const result = await service.createUser(userData);
|
|
85
|
+
|
|
86
|
+
// Assert — verify the outcome
|
|
87
|
+
expect(result.id).toBe("usr_123");
|
|
88
|
+
expect(result.email).toBe("alice@example.com");
|
|
89
|
+
expect(mockRepo.save).toHaveBeenCalledWith(userData);
|
|
90
|
+
});
|
|
91
|
+
|
|
92
|
+
it("should throw ValidationError for invalid email", async () => {
|
|
93
|
+
// Arrange
|
|
94
|
+
const userData = { email: "not-an-email", name: "Alice" };
|
|
95
|
+
const service = new UserService(mockRepo);
|
|
96
|
+
|
|
97
|
+
// Act & Assert
|
|
98
|
+
await expect(service.createUser(userData)).rejects.toThrow(ValidationError);
|
|
99
|
+
});
|
|
100
|
+
});
|
|
101
|
+
});
|
|
102
|
+
```
|
|
103
|
+
|
|
104
|
+
## 4. Naming Conventions
|
|
105
|
+
|
|
106
|
+
### Describe Blocks
|
|
107
|
+
- Top level: class or module name
|
|
108
|
+
- Nested: method or function name
|
|
109
|
+
|
|
110
|
+
### Test Names
|
|
111
|
+
Use the pattern: **"should {expected behavior} when {condition}"**
|
|
112
|
+
|
|
113
|
+
✅ Good:
|
|
114
|
+
```typescript
|
|
115
|
+
it("should return 404 when user does not exist")
|
|
116
|
+
it("should hash password before saving")
|
|
117
|
+
it("should send welcome email after registration")
|
|
118
|
+
it("should retry 3 times on network failure")
|
|
119
|
+
```
|
|
120
|
+
|
|
121
|
+
❌ Bad:
|
|
122
|
+
```typescript
|
|
123
|
+
it("test user creation") // vague, no expected behavior
|
|
124
|
+
it("works") // meaningless
|
|
125
|
+
it("createUser") // just the function name
|
|
126
|
+
it("should work correctly") // no specific behavior
|
|
127
|
+
```
|
|
128
|
+
|
|
129
|
+
## 5. Mocking Rules
|
|
130
|
+
|
|
131
|
+
### What to Mock
|
|
132
|
+
- External HTTP calls (APIs, third-party services)
|
|
133
|
+
- Database connections (for unit tests only)
|
|
134
|
+
- File system operations
|
|
135
|
+
- Time-dependent functions (Date.now, setTimeout)
|
|
136
|
+
- Email/notification services
|
|
137
|
+
|
|
138
|
+
### What NOT to Mock
|
|
139
|
+
- The code under test itself
|
|
140
|
+
- Simple utility functions
|
|
141
|
+
- Data transformations
|
|
142
|
+
- Type conversions
|
|
143
|
+
|
|
144
|
+
### Mock Discipline
|
|
145
|
+
```typescript
|
|
146
|
+
// ✅ Good: Mock at the boundary
|
|
147
|
+
const mockEmailService = { send: vi.fn().mockResolvedValue(true) };
|
|
148
|
+
const service = new UserService(mockEmailService);
|
|
149
|
+
|
|
150
|
+
// ❌ Bad: Mocking implementation details
|
|
151
|
+
vi.spyOn(service, 'validateEmail'); // testing internal method
|
|
152
|
+
```
|
|
153
|
+
|
|
154
|
+
### Rules
|
|
155
|
+
- Reset mocks between tests: `beforeEach(() => vi.clearAllMocks())`
|
|
156
|
+
- Verify mock calls when the side effect IS the behavior being tested
|
|
157
|
+
- Don't over-mock — if you're mocking more than 3 things, the code may need refactoring
|
|
158
|
+
|
|
159
|
+
## 6. Integration Test Standards
|
|
160
|
+
|
|
161
|
+
Integration tests verify that components work together correctly.
|
|
162
|
+
|
|
163
|
+
```typescript
|
|
164
|
+
describe("User Registration Flow", () => {
|
|
165
|
+
let app: Express;
|
|
166
|
+
let db: TestDatabase;
|
|
167
|
+
|
|
168
|
+
beforeAll(async () => {
|
|
169
|
+
db = await createTestDatabase();
|
|
170
|
+
app = createApp({ database: db });
|
|
171
|
+
});
|
|
172
|
+
|
|
173
|
+
afterAll(async () => {
|
|
174
|
+
await db.cleanup();
|
|
175
|
+
});
|
|
176
|
+
|
|
177
|
+
it("should register user and send confirmation email", async () => {
|
|
178
|
+
const response = await request(app)
|
|
179
|
+
.post("/api/v1/users")
|
|
180
|
+
.send({ email: "alice@test.com", name: "Alice", password: "SecureP@ss1" });
|
|
181
|
+
|
|
182
|
+
expect(response.status).toBe(201);
|
|
183
|
+
expect(response.body.data.email).toBe("alice@test.com");
|
|
184
|
+
|
|
185
|
+
// Verify side effects
|
|
186
|
+
const userInDb = await db.users.findByEmail("alice@test.com");
|
|
187
|
+
expect(userInDb).toBeTruthy();
|
|
188
|
+
});
|
|
189
|
+
});
|
|
190
|
+
```
|
|
191
|
+
|
|
192
|
+
### Rules
|
|
193
|
+
- Use a dedicated test database (never the real one)
|
|
194
|
+
- Clean up after each test suite
|
|
195
|
+
- Test the full request/response cycle
|
|
196
|
+
- Verify database state changes
|
|
197
|
+
- Test error paths, not just happy paths
|
|
198
|
+
|
|
199
|
+
## 7. E2E Test Standards
|
|
200
|
+
|
|
201
|
+
E2E tests simulate real user workflows through the UI.
|
|
202
|
+
|
|
203
|
+
### Rules
|
|
204
|
+
- Use Playwright or Cypress (team choice, be consistent)
|
|
205
|
+
- Test the top 5 user journeys (login, core workflows, payment if applicable)
|
|
206
|
+
- Use data-testid attributes for selectors (not CSS classes or text)
|
|
207
|
+
- Each test should be independent — no test-ordering dependencies
|
|
208
|
+
- Keep E2E suite under 10 minutes total runtime
|
|
209
|
+
|
|
210
|
+
```typescript
|
|
211
|
+
// ✅ Good: stable selector
|
|
212
|
+
await page.click('[data-testid="submit-button"]');
|
|
213
|
+
|
|
214
|
+
// ❌ Bad: fragile selectors
|
|
215
|
+
await page.click('.btn-primary'); // CSS class changes break this
|
|
216
|
+
await page.click('text=Submit Order'); // text changes break this
|
|
217
|
+
```
|
|
218
|
+
|
|
219
|
+
## 8. Test Data
|
|
220
|
+
|
|
221
|
+
### Factories Over Fixtures
|
|
222
|
+
Use factory functions that generate test data with sensible defaults:
|
|
223
|
+
|
|
224
|
+
```typescript
|
|
225
|
+
function createTestUser(overrides = {}) {
|
|
226
|
+
return {
|
|
227
|
+
id: `usr_${Math.random().toString(36).slice(2)}`,
|
|
228
|
+
email: `test-${Date.now()}@example.com`,
|
|
229
|
+
name: "Test User",
|
|
230
|
+
role: "user",
|
|
231
|
+
isActive: true,
|
|
232
|
+
...overrides,
|
|
233
|
+
};
|
|
234
|
+
}
|
|
235
|
+
|
|
236
|
+
// Usage
|
|
237
|
+
const admin = createTestUser({ role: "admin", name: "Admin" });
|
|
238
|
+
const inactive = createTestUser({ isActive: false });
|
|
239
|
+
```
|
|
240
|
+
|
|
241
|
+
### Rules
|
|
242
|
+
- Use unique data per test (no shared mutable state)
|
|
243
|
+
- Factory functions > static fixtures
|
|
244
|
+
- Use realistic but fake data (not "test", "foo", "bar")
|
|
245
|
+
|
|
246
|
+
## Checklist
|
|
247
|
+
|
|
248
|
+
Before submitting any code:
|
|
249
|
+
- [ ] Unit tests for all new functions/methods
|
|
250
|
+
- [ ] Tests follow AAA pattern (Arrange, Act, Assert)
|
|
251
|
+
- [ ] Test names use "should ... when ..." pattern
|
|
252
|
+
- [ ] Mocks reset between tests
|
|
253
|
+
- [ ] No test-ordering dependencies
|
|
254
|
+
- [ ] Integration tests for API endpoints
|
|
255
|
+
- [ ] Coverage meets minimum thresholds (70% unit, critical paths integration)
|
|
256
|
+
- [ ] E2E selectors use data-testid
|
|
257
|
+
- [ ] Test data uses factories, not shared mutable fixtures
|